#define 不是簡單的替換嗎,為什麼下面的代碼錯誤?
#define OP *
int main()
{
int a = 3;
a OP= 3;
// a *= 3 ??
return 0;
}
#define 的替換是在「詞語」的層面進行的,所以替換結果是類似於「a * = 3」(注意那個空格),當然出問題了
你把代碼展開就知道了,存為test.c文件,然後使用cpp處理一下,得到的結果:
ma@ma-T440p:~$ cpp test.c
# 1 "test.c"
# 1 "&
# 1 "&
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "&
# 1 "test.c"
int main()
{
int a = 3;
a * = 3;
return 0;
}
這就一目了然了么。
是詞法分析後替換,而不是文本替換實際替換規則還是有點複雜的,比如可變參,遞歸替換等
預處理(宏展開)是在詞法分析做完之後實施的,詞法分析後的結構是一個一個的token,此時OP和=是兩個token,宏展開後依然是兩個token。而如果沒有用宏而是寫成*=,詞法分析會把他們識別成一個token,即乘等操作符。希望題主能夠理解這個意思。
更新一發評論中的回答:
詞法分析器不是通過加空格來劃分token的(事實上不做詞法分析他又怎麼知道要在哪裡加空格呢?),他有自己的一套規則。對你這個例子,他遇到O後會認為這是一個標識符token的開頭(標識符是字母數字下劃線組合,且不能數字開頭),繼續往前找直到遇到一個不滿足標識符規則的字元,=不滿足所以斷到=前面,如果是空格也是一樣斷,於是識別出的token是一個內容為OP的標識符。同樣的道理,如果你寫的是OPabcd,那麼就會斷到d後面,然後識別出的token就是一個內容為OPabcd的標識符,結果就是你並不會看到他被展開成*abcd。以上要說的就是宏展開是基於詞法分析得到的token流而不是直接在原始C代碼上做的簡單字元替換。
最後教你一招:
#define OP(o) *##o使用時,如果想用乘等:
a OP(=) b;
如果想用乘:
c = a OP() b;gcc上可以,不保證別的編譯器也能編過。
手機敲代碼累死。。。可以用-traditional-cpp強行編(純種gcc,clang的不行)
% cat test.c
#define OP +void main(void) {
int i = 10; i OP= 1; printf("%d", i);}% gcc -traditional-cpp test.c -o testtest.c: In function "main":test.c:6:5: warning: implicit declaration of function "printf" [-Wimplicit-function-declaration] printf("%d
", i); ^test.c:6:5: warning: incompatible implicit declaration of built-in function "printf"test.c:6:5: note: include "&
% cat 1.c
#define OP *
int main()
{
int a = 3;
a OP= 3;
return 0
}
% gcc -E 1.c
# 1 "1.c"
# 1 "&
# 1 "&
# 329 "&
# 1 "&
# 1 "&
# 1 "1.c" 2
int main()
{
int a = 3;
a * = 3;
return 0
}
% cat 2.c
#define CONCAT_OP(op1, op2) op1 ## op2
int main()
{
int a = 3;
a CONCAT_OP (*, =) 3;
return 0
}
% gcc -E 2.c
# 1 "2.c"
# 1 "&
# 1 "&
# 329 "&
# 1 "&
# 1 "&
# 1 "2.c" 2
int main()
{
int a = 3;
a *= 3;
return 0
}
推薦閱讀:
※當把一個char類型轉換成int型的時候計算機里究竟而發生了什麼?
※OpenMP在實際開發中應用多嗎?
※對於 C/C++ 函數指針的困惑?
※有沒有使用「==」判斷浮點數相等與否出現錯誤的例子?
※怎樣開發一款有限元軟體,從哪些方面學習?