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.
Related
Good day,
I've faced with a strange problem while compiling very simple C++ program which leverages recursive macros expansion:
#define FINAL(a1, a2, a3) const char *p = "final values are: " #a1 " " #a2 " " #a3;
#define SPLIT(a1, a2) a1, a2
#define BRACES(a1, a2) ( a1, a2 )
#define START(macro, a1, a2) macro BRACES(a1, SPLIT a2)
START(FINAL, 1, (2, 3))
int main(int argc, char* argv[])
{
std::cout << p << std::endl;
return 0;
}
The program is expecting to print "final values are: 1 2 3" text. And it does on a Visual Studio 2008.
But I see an issue when trying to compile it with mingw32 gcc-6.3 on Windows 7 and with gcc-5.4 on Linux Ubuntu-16:
$ g++ -I /e/dev-libs/boost/boost_1_60_0-mingw32/include/boost-1_60 test.cpp
test.cpp:7:24: error: expected constructor, destructor, or type conversion before '(' token
#define BRACES(a1, a2) ( a1, a2 )
^
test.cpp:8:36: note: in expansion of macro 'BRACES'
#define START(macro, a1, a2) macro BRACES(a1, SPLIT a2)
^~~~~~
test.cpp:12:1: note: in expansion of macro 'START'
START(FINAL, 1, (2, 3))
^~~~~
It looks like it doesn't depend on a C++ standard, I've tried -std=c++11 and -std=c++03 with gcc. I've reread part 16.3 "Macro replacement" of C++ 11 standard a few times, but I guess I've missed something important there.
What can be wrong here with the code?
One more important thing: BOOST_PP_SEQ_FOR_EACH_I_R from boost preprocessor library can't be compiled too, which is more than strange:
#include <iostream>
#include <boost/preprocessor/seq/for_each_i.hpp>
#define FINAL2(r, data, id, value) const char *p ## id = #value;
BOOST_PP_SEQ_FOR_EACH_I_R(_, FINAL2, _, (a)(b)(c))
int main()
{
std::cout << p1 << std::endl;
return 0;
}
Error output:
$ g++ -I /e/dev-libs/boost/boost_1_60_0-mingw32/include/boost-1_60 -std=c++03 test2.cpp
In file included from test2.cpp:2:0:
E:/dev-libs/boost/boost_1_60_0-mingw32/include/boost-1_60/boost/preprocessor/seq/for_each_i.hpp:96:96: error: expected constructor, destructor, or type conversion before '(' token
# define BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EXEC(r, macro, data, seq) BOOST_PP_FOR_ ## r((macro, data, seq, 0, BOOST_PP_SEQ_SIZE(seq)), BOOST_PP_SEQ_FOR_EACH_I_P, BOOST_PP_SEQ_FOR_EACH_I_O, BOOST_PP_SEQ_FOR_EACH_I_M)
^
E:/dev-libs/boost/boost_1_60_0-mingw32/include/boost-1_60/boost/preprocessor/control/iif.hpp:32:31: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EXEC'
# define BOOST_PP_IIF_1(t, f) t
^
E:/dev-libs/boost/boost_1_60_0-mingw32/include/boost-1_60/boost/preprocessor/control/iif.hpp:25:39: note: in expansion of macro 'BOOST_PP_IIF_1'
# define BOOST_PP_IIF_I(bit, t, f) BOOST_PP_IIF_ ## bit(t, f)
^~~~~~~~~~~~~
The problem with first example seems to be rather straightforward. After first expansion preprocessing will stop doing what you want it to do:
START(FINAL, 1, (2, 3))
// becomes
FINAL BRACES(1, SPLIT (2, 3))
There are no arguments for FINAL so generated code will be messed up.
As #VTT says, the replacement for START(FINAL, 1, (2, 3)) is FINAL BRACES(1, SPLIT(2, 3)); that text is then rescanned, but it does not have the form of a macro expansion of FINAL.
You can achieve the effect you want with another level of indirection (or macro expansion, to be more precise):
#define SPLIT(a1, a2) a1, a2
#define BRACES(a1, a2) ( a1, a2 )
#define APPLY(a1, a2) a1 a2
#define START(macro, a1, a2) APPLY(macro, BRACES(a1, SPLIT a2))
Using the rules specified by the standard, your macro:
START(FINAL, 1, (2, 3))
...expands during argument substitution to:
FINAL BRACES(1, SPLIT (2, 3))
This is then rescanned during rescan and further replacement; during this step, FINAL is seen, but it doesn't have arguments after it. Since you only have a function-like macro, nothing happens. So the CPP moves along. BRACES however has two arguments, and is a two argument function-like macro, so it expands (SPLIT's expansion is part of this expansion), leaving you with this:
FINAL (1, 2, 3)
...and now the CPP is done with BRACES, so it moves along further. There's no step to back up and evaluate/expand FINAL. If you want that to happen, you need an indirect macro (such as the one #rici showed you).
That Microsoft's CPP expands this isn't surprising; MS's CPP is non-standard.
As for the second question (really should be a separate question though):
BOOST_PP_SEQ_FOR_EACH_I_R(_, FINAL2, _, (a)(b)(c))
That call is wrong. The _R variant macros expect an r argument that corresponds to macro sets (this is the first argument). These are numbers; they can't just be _. 1 would work; however, you don't actually need to call the _R version unless you're doing something recursive/complex.
I have the following syntax for run-time type identification:
if RTTI_FUNC( c, short, myFunc );
else if RTTI_FUNC( c, float, myFunc );
else if RTTI_FUNC( c, complex<short>, myFunc );
else if RTTI_FUNC( c, complex<float>, myFunc );
where RTTI_FUNC is defined in another file as
#define RTTI_FUNC(in,type,func) \
( dynamic_cast<MyClass< type >* >(in) ) \
func( *(reinterpret_cast<MyClass< type >* >(in)) )
When I run
cppcheck . --force --enable=all -q
it reports
(error) syntax error
for the if RTTI_FUNC( c, short, myFunc ); line
The error is a false positive. Is there any way to ignore it or suppress it other than using an inline suppression? Possibly with a rule or regex?
Alternatively, is it possible to expand the macro to correct the false positive?
You can use -I <path/to/include/dir> which will allow cppcheck to expand the macro
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))
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.
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.