Search code examples
cgcc

Can we use "#elif !" in c?


I am confused by the code in sprng2.0 and it gives me compile errors on my machine after I make. It seems that my compiler(gcc 4.7.3) doesn't support #elif !, what does #elif ! mean? Or could I just replace it with #ifndef ?

#ifdef SYNC
if(expJ[dE]>sprng(genptr[k]))
#elif !SYNC
if(dE<=0 || expJ[dE]>sprng(genptr[k]))
#endif

The error message is error: operator '!' has no right operand I have tested,

#ifdef SYNC
if(expJ[dE]>sprng(genptr[k]))
#elif !(SYNC)
if(dE<=0 || expJ[dE]>sprng(genptr[k]))
#endif

It gives me the error: missing expression between '(' and ')'


Solution

  • The code in your question:

    #ifdef SYNC
    /* ... */
    #elif !SYNC
    /* ... */
    #endif
    

    may or may not work. It will fail in the way you indicate if the macro SYNC is defined as nothing (not undefined, but defined to expand to a sequence of no tokens).

    But it's an odd way to write it.

    #ifdef SYNC tests whether SYNC is defined or not, without regard to how it's defined.

    #elif !SYNC tests whether SYNC expands to an expression with a false value. If SYNC is not defined at all, the preprocessor will expand the identifier SYNC to 0, and #elif !0 is perfectly legal. But if SYNC is defined to expand to something that's not a valid operand of !, then you'll get an error.

    For example, if I compile the above with either gcc ... or gcc -DSYNC ... (the latter defines SYNC as 1), then there's no error, and I get either the first or the second block of code.

    But if I compile it with gcc -DSYNC= ..., which defines SYNC as an empty token sequence, then the #elif expands to:

    #elif !
    

    which is a syntax error. Adding parentheses doesn't help; it just changes the error message.

    The real problem, I think, is that you're mixing a test for whether SYNC is defined or not with a test for whether its value is true or false.

    You very probably don't need the #elif; just #else will do.

    If you want to choose which chunk of code to compile based on whether SYNC is defined, just write:

    #ifdef SYNC
    /* ... */
    #else
    /* ... */
    #endif
    

    If you want to test whether SYNC is true or false (and noting that if SYNC is not defined as a macro it expands to 0), you can write:

    #if SYNC
    /* ... */
    #else
    /* ... */
    #endif
    

    You can use either form, but I personally would prefer the #ifdef (unless there's some meaningful distinction between different defined values of SYNC).

    Note that the preprocessor has #ifdef and #ifndef directives, but it doesn't have #elifdef or #elifndef (but the upcoming C23 standard, not yet published as I type this, will add them). If you need to test for definedness in a #else, just use the defined operator:

    ...
    #elif defined(SYNC)
    ...
    

    But I don't think you need to do that in this case.