2013-05-20 132 views
1

我在讀書學習C。在這本書中,以下示例代碼給出了gcc(Debian 4.7.2-4)4.7.2的預處理器錯誤。錯誤是:預處理器無效的預處理器令牌錯誤

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

的代碼是:

#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; 
} 

是gcc的預處理程序不能正確地做這個或者是蹊蹺的是需要改變的代碼?

+0

我在想這是打亂了事情的printfs。 – Marvo

+1

不,這是#elif行有問題。例如,預處理器正在將第一個#elif擴展爲'#elif「我知道C語言。\ n」=='C''然後失敗。 [ideone也不行。](http://ideone.com/TkzvEk) – cebarth

+0

到目前爲止給出的答案都可以使用。但是,我必須說,如果這是一本書的例子,那麼您可能需要重新考慮您正在使用的書。 – cebarth

回答

2

由於@cebarth指出,問題是,你在第一#if重新定義C_LANGB_LANG之後,#elif條款失敗,因爲擴張:

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

C標準說,這對#if#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.

沒有不評價,因爲提早辦理入住手續的表達何況有成功。

解決此問題的一種方法是在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' 

另一種方式來解決,這是明確使用#else代替#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 
+2

不是真正的問題:爲什麼預處理器在'if'成功後執行'elif'代碼? – rliu

+0

我不認爲它正在執行它,而只是解析該行。雖然看起來有點傻。 – cebarth

+0

@roliu:C標準只說明##if和#elif表達式被評估,並且不會因爲之前的#if或elif已經匹配而給出任何異常。我會更新答案。 – jxh

0
#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; 
} 
0

一般混合預處理代碼和非預處理程序代碼是不是一個好主意,因爲它很難跟隨執行路徑(當然,最次)。

爲了您的具體的例子有什麼可以做,以使事情更容易:

#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 

無需使用宏定義。你可以改變什麼,通過簡單地增加一個字符eiter C_LANG或B_LANG打印出來:

#define C_LANGn 
#define B_LANGn 

這樣的代碼是更具可讀性。