简体   繁体   中英

Preprocessor invalid preprocessor token error

I am reading a book to learn C . In that book is the following example code giving a preprocessor error with gcc (Debian 4.7.2-4) 4.7.2. The error is:

file.c: In function 'main':
file.c:16:14: error: token ""I know the C language.\\n"" is not valid in preprocessor expressions
file.c:20:14: error: token ""I know BASIC.\\n"" is not valid in preprocessor expressions

The code is:

#include <stdio.h>

#define C_LANG    'C'
#define B_LANG    'B'
#define NO_ERROR  0

int main(void)
{
   #if C_LANG == 'C' && B_LANG == 'B'
     #undef C_LANG
     #define C_LANG "I know the C language.\n"
     #undef B_LANG
     #define B_LANG "I know BASIC.\n"
     printf("%s%s", C_LANG, B_LANG);
   #elif C_LANG == 'C'
     #undef C_LANG
     #define C_LANG "I only know C language.\n"
     printf("%s", C_LANG);
   #elif B_LANG == 'B'
     #undef B_LANG
     #define B_LANG "I only know BASIC.\n"
     printf("%s", B_LANG);
   #else
     printf("I don't know C or BASIC.\n");
   #endif

   return NO_ERROR;
}

Is the gcc preprocessor incapable of doing this correctly or is the something wrong with the code that needs to be changed?

As @cebarth points out, the problem is that after you redefined C_LANG and B_LANG in the first #if , the #elif clauses fail, because the expansion is:

   #elif "I know the C language.\n" == 'C'
   /*...*/
   #elif "I know BASIC.\n" == 'B'

The C Standard says this about #if and #elif (C99 6.10.1):

Preprocessing directives of the forms
# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt
check whether the controlling constant expression evaluates to nonzero.

There is no mention of not evaluating the expression because of an earlier check having succeeded.

One way to fix this is to redefine them back after the printf() .

     #undef C_LANG
     #define C_LANG "I know the C language.\n"
     #undef B_LANG
     #define B_LANG "I know BASIC.\n"
     printf("%s%s", C_LANG, B_LANG);
     #undef C_LANG
     #define C_LANG 'C'
     #undef B_LANG
     #define B_LANG 'B'

Another way to fix this is to explicitly use #else instead of #elif .

   #if C_LANG == 'C' && B_LANG == 'B'
     #undef C_LANG
     #define C_LANG "I know the C language.\n"
     #undef B_LANG
     #define B_LANG "I know BASIC.\n"
     fprintf(stdout, "%s%s", C_LANG, B_LANG);
   #else
     #if C_LANG == 'C'
       #undef C_LANG
       #define C_LANG "I only know C language.\n"
       printf("%s", C_LANG);
     #elif B_LANG == 'B'
       #undef B_LANG
       #define B_LANG "I only know BASIC.\n"
       printf("%s", B_LANG);
     #else
       printf("I don't know C or BASIC.\n");
     #endif
   #endif
#include <stdio.h>

#define C_LANG    'C'
#define B_LANG    'B'
#define NO_ERROR  0

int main(void)
{
   #if C_LANG == 'C' && B_LANG == 'B'
     #define C_LANG_VALUE "I know the C language.\n"
     #define B_LANG_VALUE "I know BASIC.\n"
     printf("%s%s", C_LANG_VALUE, B_LANG_VALUE);
   #elif C_LANG == 'C'
     #define C_LANG_VALUE "I only know C language.\n"
     printf("%s", C_LANG_VALUE);
   #elif B_LANG == 'B'
     #define B_LANG_VALUE "I only know BASIC.\n"
     printf("%s", B_LANG_VALUE);
   #else
     printf("I don't know C or BASIC.\n");
   #endif

   return NO_ERROR;
}

Generally mixing preprocessor code and non-preprocessor code is not a good idea because it's hard to follow the execution path (well, most times).

For your particular example there is something you can do to make things easier:

#define C_LANG 
#define B_LANG  
#define NO_ERROR

#if defined(C_LANG) || defined (B_LANG)
   #if defined(C_LANG)
       printf ("I know the C language.\n");
   #else
       printf ("I know the BASIC language.\n");
   #endif
#else
   printf("I don't know C or BASIC.\n");
#endif

No need to use macro definitions. You can change what is printed out by simply adding one character to eiter C_LANG or B_LANG:

#define C_LANGn
#define B_LANGn 

This way the code is much more readable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM