In C++ is there a mechanism to allow non terminated macros to be expressed?
This is a contrived example:
#define MACRO(x, y) x + y
#define MACROC1(x) MACRO(x,
#define MACROC2(y) y)
//...expecting 3
int foo = MACROC1(1) MACROC2(2);
I receive the error improperly terminated macro invocation from MSVC.
When I run cl -E file.cpp I see that the code below has been generated:
int c = 1 + 1 + 2);
In visual studio compilation fails with errors:
error C2059: syntax error : ')'
IntelliSense: improperly terminated macro invocation
I don't think this is possible. The C precompiler expands macros depth-first, so the MACROC1 will be full expanded before the MACROC2 is even considered. Then, it will find the MACRO with and incomplete argument list and throws an error.
Generally speaking, you should avoid defining macros that build other macro calls. Compilers tend not to agree in what those mean.
Your code would translate to :
int foo = MACRO(1, 2;
Which is wrong - it is an incomplete (improperly terminated) invocation of macro MACRO.
Related
The following C++ example fails to compile with gcc or clang, but only generates a warning with ICC, and nothing at all with MSVC:
int main(int argc, char *argv[])
{
if (argc < 2)
goto clean_up;
#if 1 // FAIL
int i = 0;
#elif 0 // workaround - OK
{
int i = 0;
}
#else // workaround - OK
int i;
i = 0;
#endif
clean_up:
return 0;
}
g++:
init.cpp:13: error: jump to label ‘clean_up’
init.cpp:4: error: from here
init.cpp:7: error: crosses initialization of ‘int i’
clang++:
init.cpp:4:9: error: cannot jump from this goto statement to its label
goto clean_up;
^
init.cpp:7:9: note: jump bypasses variable initialization
int i = 0;
^
ICC:
init.cpp(4): warning #589: transfer of control bypasses initialization of:
variable "i" (declared at line 7)
goto clean_up;
^
I understand the cause of the error, and for a simple example such as this it is fairly easy to work around (I've included a couple of possible workarounds in the example above), but I'm working on a large cross-platform legacy code base that is peppered with error-handling macros which use a similar goto construct. Other developers working with MSVC or ICC keep introducing inline initialisations which subsequently result in errors for gcc or clang builds (and of course they just ignore the warnings they get with MSVC/ICC).
So I need to find a way to either (a) make such cases result in errors on ICC/MSVC or (b) reduce them to warnings with gcc/clang. I tried -fpermissive with gcc but that doesn't seem to help.
For extra credit I'm also curious as to the rationale behind this error for simple scalar initialisation - I can see why jumping over a constructor might be problematic, but initialising an int as in the above example doesn't seem like it could ever be an issue, and simply splitting the definition+initialisation into a definition + assignment makes the error go away?
The MSVC flag for treating a warning as en error is /we n where n is the number of the warning.
For example, /we4326 flags warning number C4326 as an error.
See https://msdn.microsoft.com/en-us/library/thxezb7y.aspx for details.
Let's consider:
#define PARENTHESIS1 (
#define PARENTHESIS2 )
#define macro_test_0(arg1, arg2) int arg1 arg2
#define macro_test_1(arg1, arg2) macro_test_0(arg1, arg2)
macro_test_0(PARENTHESIS1, PARENTHESIS2 ;) //->works fine
macro_test_1(PARENTHESIS1, PARENTHESIS2 ;) //doesn't work
For macro_test_1 I have error message: "Macro argument mismatch", "Too few arguments provided to function-like invocation method", "Use of undeclared identifier 'macro_test_0' ".
Thing is, for macro_test_0, example gives:
int ( ) ;
which is ok, but macro_test_1 example gives (if I'm correct):
macro_test_0((,) ;)
which is obviously wrong. I'd like arg1 and arg2 of the macro to prevent expansion, in order to keep:
macro_test0(PARENTHESIS1, PARENTHESIS2 ;)
I guess it's related to macro expansion order, but is there a way or trick to achieve this ? I tried several things such as artificial (ie useless) concatenation of arguments to delay expansion during macro invocation but without success.
i don't know which compiler or IDE u use.
but for visual studio 2012: both line generate same code after preprocessing
int ( ) ;
int ( ) ;
for vs:
'src file' property -> C/C++/Preprocessor -> preprocess to a file
option will output code after preprocessing to a file
GCC have similar compile options.
While porting a project from Visual Studio 2005 to 2013, I came across this strange behaviour for which I cannot find an explanation. The context was about creating template specializations by including a certain header file multiple times, but changing preprocessor definitions before each include to basically generate a different class declaration.
I could narrow down the issue to the following situation:
gen.hpp
#ifdef ENABLE_GEN
#ifdef GEN_SWAP_ORDER // (1)
class Foo {};
#else
class Bar {};
#endif
#endif
main.cpp
#define ENABLE_GEN
#include "gen.hpp"
#define GEN_SWAP_ORDER
#include "gen.hpp"
int main()
{
Foo foo;
Bar bar;
}
This works as expected, i.e. both Foo and Bar are declared and usable in main().
Now, to cause the issue, change the #ifdef in the line marked by (1) to #ifndef, which should effectively only cause the order in which Foo and Bar are declared to be swapped. But instead, compilation then fails:
1>c:\path\to\main.cpp(10): error C2065: 'Bar' : undeclared identifier
1>c:\path\to\main.cpp(10): error C2146: syntax error : missing ';' before identifier 'bar'
1>c:\path\to\main.cpp(10): error C2065: 'bar' : undeclared identifier
The preprocessed file looks like this (stripped some whitespace):
#line 1 "c:\\path\\to\\main.cpp"
#line 1 "c:\\path\\to\\gen.hpp"
class Foo {};
#line 8 "c:\\path\\to\\gen.hpp"
#line 10 "c:\\path\\to\\gen.hpp"
#line 4 "c:\\path\\to\\main.cpp"
int main()
{
Foo foo;
Bar bar;
}
My question is: Am I missing something? Is this expected behaviour for some reason? Is it a compiler setting/bug that makes Visual Studio skip the header contents (including the #else part) a second time when it thinks it has a header guard (because of the #ifndef)?
Thanks!
This is MS Connect issue 800200 as per dyp's comment, and was fixed in VS2013 RTM.
Is there a way that I can force a preprocessor macro in C++ to emit an error? What I would like to do is define a macro UNKNOWN. I'm writing some code for a robot, and I don't yet know where all of the electronics are being plugged in. I'd like to be able to define the ports in some header file, like
const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
//etc.
However, when I reach a port that I don't yet know, I want to be able to write something like
const int LED_PORT = UNKNOWN;
In debug mode, UNKNOWN would just be defined to some arbitrary value, like 0. However, when compiling in release mode, I want it to throw an error when UNKNOWN is used, so that unassigned ports don't end up in the final release. I know I can use the #error directive to force an error, but can I do something similar in a macro?
I've seen a solution using static_assert, but I unfortunately can't use C++11 for this platform.
Since #error can't result from a macro expansion, you can ensure that the macro expands to something that must be diagnosed, like a syntax error.
For example:
#ifdef RELEASE
#define UNKNOWN #Invalid_use_of_UNKNOWN
#else
#define UNKNOWN 0
#endif
const int MOTOR_PORT = 1;
const int FAN_PORT = 2;
const int LED_PORT = UNKNOWN;
int main(void) {
int x = LED_PORT;
}
The # character isn't part of C's basic character set, so its appearance outside a comment, character constant, or string literal should always result in an error message. ($ would work, except that accepting $ in identifiers is a common extension. ` would probably also work, but # stands out better.)
I've defined the macro so it produces a reasonable error message with gcc:
c.c:9:1: error: stray ‘#’ in program
c.c:9:22: error: ‘Invalid_use_of_UNKNOWN’ undeclared here (not in a function)
and with clang:
c.c:9:22: error: expected expression
const int LED_PORT = UNKNOWN;
^
c.c:2:17: note: expanded from:
#define UNKNOWN #Invalid_use_of_UNKNOWN
^
1 error generated.
(There's a _Pragma operator corresponding to the #pragma directive. It would be nice if there were an _Error operator as well, but there isn't.)
Well, this does not produce a complier error message like #error, but would compile in debug and fail in release:
#ifdef _DEBUG
# define UNKNOWN 1
#else
# define UNKNOWN
#endif
const int port1 = UNKNOWN; // fail in release
You could make a division by zero which will throw a compiler error:
#define UNKNOWN 0/0
The sizeof operator cannot be applied to an incomplete type, so try this:
// Declared, but not defined anywhere.
struct illegal_use_of_unknown_macro;
#define UNKNOWN (sizeof (illegal_use_of_unknown_macro))
I have the following definitions:
template<typename T1, typename T2>
class Test2
{
public:
static int hello() { return 0; }
};
template<typename T>
class Test1
{
public:
static int hello() { return 0; }
};
#define VERIFY_R(call) { if (call == 0) printf("yea");}
With these, I try to compile the following:
VERIFY_R( Test1<int>::hello() );
this compiles fine
VERIFY_R( (Test2<int,int>::hello()) );
this also compiles fine, notice the parentheses around the call.
VERIFY_R( Test2<int,int>::hello() );
This, without the parentheses produces a warning and several syntax errors:
warning C4002: too many actual parameters for macro 'VERIFY_R'
error C2143: syntax error : missing ',' before ')'
error C2059: syntax error : ')'
error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before '}'
error C2143: syntax error : missing ';' before '}'
fatal error C1004: unexpected end-of-file found
What's going on here?
This happens with VS2008 SP1.
The comma inside a macro can be ambiguous: an extra set of parentheses (your second example) is one way of disambiguating. Consider a macro
#define VERIFY(A, B) { if ( (A) && (B) ) printf("hi"); }
then you could write VERIFY( foo<bar, x> y ).
Another way of disambiguating is with
typedef Test1<int,int> TestII;
VERIFY_R( TestII::hello() );
The preprocessor is a dumb text replacement tool that knows nothing about C++. It interprets
VERIFY_R( Test1<int,int>::hello() );
as
VERIFY_R( (Test1<int), (int>::hello()) );
which calls VERIFY_R with too many parameters. As you noted, additional parentheses fix this:
VERIFY_R( (Test1<int,int>::hello()) );
The question remains, however, why you need the preprocessor anyway. The macro you used in your question could just as well be an inline function. If you real code doesn't do anything requiring the preprocessor, try to get rid of macros. They just cause pain.
The comma in <int, int> is treated as an argument separator for the macro, rather than for the template. The compiler therefore thinks you're calling VERIFY_R with two arguments (Test1<int and int>::hello()), when it requires only one. You need to use variadic macros to expand everything supplied to the macro:
#define VERIFY_R(...) { if ((__VA_ARGS__) == 0) printf("yea");}
It is generally a good idea to wrap macro arguments in parentheses, as well, to prevent other kinds of weird substitution errors.
The preprocessor doesn't know that < and > are supposed to be brackets, so it interprets the expression as two macro arguments, Test1<int and int>::hello(), separated by the ,. As you say, it can be fixed by surrounding the entire expression with parentheses, which the preprocessor does recognise as brackets.
I'm not sure if this is an error in your reporting here or the actual problem, but your last VERIFY_R is still referencing Test1, rather than Test2.