The macro expands correctly, but gives me the "expected expression"

I made a trivial reduction to my problem:

#define STR_BEG " #define STR_END " int main() { char * s = STR_BEG abc STR_END; printf("%s\n", s); } 

When compiling, I get the following error:

 static2.c:12:16: error: expected expression char * s = STR_BEG abc STR_END; ^ static2.c:7:17: note: expanded from macro 'STR_BEG' #define STR_BEG " 

Now, if I just started the preprocessor, gcc -E myfile.c , I get:

 int main() { char * s = " abc "; printf("%s\n", s); } 

This is exactly what I wanted, and a perfectly legitimate result code. So what is the deal?

+7
c macros c-preprocessor
source share
1 answer

A macro does not really expand โ€œcorrectlyโ€ because it is not a valid C-preprocessor program. According to Kerrek, the preprocessor does not work on arbitrary sequences of characters - it works on whole tokens. Tokens are punctuation characters, identifiers, numbers, strings, etc. The same forms (more or less) like those that form a valid C code. These definitions do not describe valid lines โ€” they open them and do not close them to the end of the line. Thus, an invalid sequence of tokens is passed to the preprocessor. The fact that he manages to release products from an invalid program is probably very convenient, but this does not make it right and almost certainly guarantees that garbage leaves the preprocessor at best. You must break your lines to form whole tokens - right now they are forming garbage input.

To actually wrap the token or sequence of tokens in quotation marks, use the operator with the string # :

 #define STRFY(A) #A STRFY(abc) // -> "abc" 

GCC and similar compilers will warn you about errors like this if you compile or a preprocessor with the -Wall flag -Wall .

(I assume that you only get errors when you try to compile as C, but not when you do it in two passes, because internally for the compiler it stores information that these are โ€œbrokenโ€ tokens that are lost if you write out the intermediate file and then compile the pre-processed source in the second pass ... if so, this is an implementation detail, do not rely on it.)


One possible solution to your real problem might look like this:

 #define LPR ( #define start STRFY LPR #define end ) #define STRFY(A) #A #define ID(...) __VA_ARGS__ ID( char * s = start()()()end; // -> char * s = "()()()"; ) 

However, an ID wrapper is required. There is no way to do this without this (it can go around any number of lines or even your entire program, but it should exist for reasons that are well covered in other issues).

+10
source share

All Articles