Macro expands correctly, but gives me "expected expression" error

11,239

The macro isn't really expanding "correctly", because this isn't a valid C Preprocessor program. As Kerrek says, the preprocessor doesn't quite work on arbitrary character sequences - it works on whole tokens. Tokens are punctuation characters, identifiers, numbers, strings, etc. of the same form (more or less) as the ones that form valid C code. Those defines do not describe valid strings - they open them, and fail to close them before the end of the line. So an invalid token sequence is being passed to the preprocessor. The fact it manages to produce output from an invalid program is arguably handy, but it doesn't make it correct and it almost certainly guarantees garbage output from the preprocessor at best. You need to terminate your strings for them to form whole tokens - right now they form garbage input.

To actually wrap a token, or token sequence, in quotes, use the stringification operator #:

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

GCC and similar compilers will warn you about mistakes like this if you compile or preprocess with the -Wall flag enabled.

(I assume you only get errors when you try to compile as C, but not when you do it in two passes, because internally to the compiler, it retains the information that these are "broken" tokens, which is lost if you write out an intermediate file and then compile the preprocessed source in a second pass... if so, this is an implementation detail, don't rely on it.)


One possible solution to your actual 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 = "()()()";
)

The ID wrapper is necessary, though. There's no way to do it without that (it can go around any number of lines, or even your whole program, but it must exist for reasons that are well-covered in other questions).

Share:
11,239
Francisco Ryan Tolmasky I
Author by

Francisco Ryan Tolmasky I

Updated on June 18, 2022

Comments

  • Francisco Ryan Tolmasky I
    Francisco Ryan Tolmasky I almost 2 years

    I've made a trivial reduction of my issue:

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

    When compiling this, 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 run the preprocessor, gcc -E myfile.c, I get:

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

    Which is exactly what I wanted, and perfectly legal resultant code. So what's the deal?

  • Francisco Ryan Tolmasky I
    Francisco Ryan Tolmasky I almost 10 years
    As I asked Kerek, then why does the preprocessor not report any errors? If its truly a preprocessor issue, I'd expect an error at the preprocessing phase, not an error from the later stage of compilation. It appears to succeed preprocessing, then choke when attempting to parse the resulting code.BTW, #x doesn't really help me since this is a very simple reduction of the code in question. If you want to know, I want to turn start()()()end into "()()()". As such Ill never be able to pass those parens to a macro. (its for a language game thing, don't ask me the ultimate practical purpose of this)
  • Leushenko
    Leushenko almost 10 years
    You can modify any sequence of valid tokens with # - pass the ()()() to it instead (instead of expanding start and end to quotes, expand them to STRFY( and ) as a nested expansion). Your preprocessor should be reporting errors on the original code - mine does - because this is invalid CPP as well as C. I guess you have a more lenient one. Try turning up the warning level?
  • M.M
    M.M almost 10 years
    @user3870686 your question is specific to quote marks (since identification of string literals happens before preprocessor token replacement). If the "real problem" does not involve quote marks then this question didn't help it.
  • Francisco Ryan Tolmasky I
    Francisco Ryan Tolmasky I almost 10 years
    I literally need it to look like start()()()end. Again, this is for a language challenge thing, I am aware that it is a ridiculous requirement. Thanks for the info though