C語言中#和##操作符用法
答:在C語言中,#
和##
是預處理器(preprocessor)的操作符,主要用于宏(macro)的定義中。這兩個操作符提供了字符串化和字符串連接的功能。
#操作符
#
操作符用于將其后的宏參數轉換為一個字符串字面量,在編譯時將宏參數轉換為字符串。
下面根據一個簡單的示例分析一下。
#include <stdio.h>#define STRINGIFY(str) #strint main(void)
{printf("STRINGIFY(hello)=%s\n", STRINGIFY(hello));return 0;
}
執行如下預處理命令:
gcc -E main.c -o main.i
查看main.i
文件,可以發現確實將宏轉換為了字符串:
...
# 5 "main.c"
int main(void)
{printf("STRINGIFY(hello)=%s\n", "hello");return 0;
}
編譯成可執行文件,運行測試:
$ gcc main.c -o main
$ ./main
STRINGIFY(hello)=hello
##操作符
##
操作符將兩個標識符連接在一起,在編譯時進行標識符連接。
下面根據一個簡單的示例分析一下。
#include <stdio.h>#define CONCAT(x, y) x##yint main(void)
{int ab = 1;printf("CONCAT(a,b)=%d\n", CONCAT(a,b));return 0;
}
執行如下預處理命令:
gcc -E main.c -o main.i
查看main.i
文件,可以發現確實將宏參數進行了連接:
...
# 5 "main.c"
int main(void)
{int ab = 1;printf("CONCAT(a,b)=%d\n", ab);return 0;
}
編譯成可執行文件,運行測試:
$ gcc main.c -o main
$ ./main
CONCAT(a,b)=1
注意
如果宏參數也是另外一個宏時,比如上面的str
或者x
和y
也是定義的一個宏:
#include <stdio.h>#define STRINGIFY(str) #str
#define CONCAT(x, y) x##y#define HELLO hello
#define A a
#define B bint main(void)
{int ab = 1;printf("STRINGIFY(hello)=%s\n", STRINGIFY(HELLO));printf("CONCAT(a,b)=%d\n", CONCAT(A,B));return 0;
}
上面STRINGIFY(HELLO)
就直接展開為大寫字符串HELLO
,而 CONCAT(A,B)
會被展開為AB
,導致編譯失敗,找不到變量AB
,這就說明當宏參數是另一個宏的時候,宏定義里有用#
或##
的地方宏參數是不會再展開。
...
# 10 "main.c"
int main(void)
{int ab = 1;printf("STRINGIFY(hello)=%s\n", "HELLO");printf("CONCAT(a,b)=%d\n", AB);return 0;
}
解決辦法是再定義一層中間轉換宏,保證所有的宏參數在這個轉換宏中展開,如下:
#include <stdio.h>#define _STRINGIFY(str) #str
#define STRINGIFY(str) _STRINGIFY(str)#define _CONCAT(x, y) x##y
#define CONCAT(x, y) _CONCAT(x, y)#define HELLO hello
#define A a
#define B bint main(void)
{int ab = 1;printf("STRINGIFY(hello)=%s\n", STRINGIFY(HELLO));printf("CONCAT(a,b)=%d\n", CONCAT(A,B));return 0;
}
編譯預處理即可按照期望進行展開:
...
# 13 "main.c"
int main(void)
{int ab = 1;printf("STRINGIFY(hello)=%s\n", "hello");printf("CONCAT(a,b)=%d\n", ab);return 0;
}
編譯成可執行文件,運行測試:
$ gcc main.c -o main
$ ./main
STRINGIFY(hello)=hello
CONCAT(a,b)=1