文章转自:https://www.cnblogs.com/wb-DarkHorse/p/3588787.html
一个题目:
首先已知#define A “hello”
#define B “world”
如何使用宏A,B表示出字符串"helloworld"
答案1:#define C A B
答案2:#define C(a,b) a##b
#define C(a,b) C(a,b)
验证:
答案1验证:
例如使用宏预编译案例:
#include <stdio.h>
#define A "hello"
#define B "world"
#define STR A B
int main(int argc,char *argv[]){
char *p = STR;
return 0;
}
预编译:
gcc -E hell.c -o hello.i
cat hello.i
预编译之后的数据查看:
...
# 7 "hello.c"
int main(int argc,char *argv[]){
char *p = "hello" "world";
return 0;
}
可知答案一并不正确。
答案2验证:
#include <stdio.h>
#define A "hello"
#define B "world"
#define _C_(a,b) a##b
#define C(a,b) _C_(a,b)
int main(int argc,char *argv[]){
char *p = C(A,B);
printf("%s\n",p);
return 0;
}
首先为什么要定义两个宏,一个不能解决吗?是的,不能。参见:(短小精悍的宏)http://www.cnblogs.com/wb-DarkHorse/archive/2013/04/27/3046749.html
按照上边的编译之后出现了错误信息:
hello.c: In function ‘main’:
hello.c:3:11: error: pasting ""hello"" and ""world"" does not give a valid preprocessing token
#define A "hello"
^
...
解决,Google之后,可以参见:问题
并且里面说了,这种情况在VS里面不会报错,可以直接工作。
#include <stdio.h>
#define A "hello"
#define B "world"
#define _C_(a,b) a##b
#define C(a,b) _C_(a,b)
int _tmain(int argc, _TCHAR* argv[])
{
char *p = C(A,B);//STR;
printf("%s\n", p);
return 0;
}
果然给出了结果:menuosd
为什么gcc和VS会对这个问题给出差异的结果呢?看这个问题:that’s why
根据C标准,用##操作之后的结果必须是一个已经定义过的符号。否则是未定义的。所以gcc和vs对于这个未定义的行为表示了不同的看法,前者是给出了错误,后者是一笑而过。name为什么是预定过的符号呢?它包含了这些内容:头文件名,等式,预处理数学,字符常数,字符串值,标点符号,单个非空字符等。
在给出的例子中,C(a,b)使用##连接之后,应该产生helloworld,但是这是一个未预定的字符串,所以产生了一个未定义行为。再看一个例子:
#include <stdio.h>
#define A 2
#define _CONS(a,b) (a##e##b)
#define CONS(a,b) _CONS(a,b)
int main(int argc,char *argv[]){
printf("%f\n",CONS(A,A));
return 0;
}
这个时候gcc不会给出错误的提示。结果是:200.000000
为什么这个不给出错误的提示:理解是:CONS(A,A)替换成为2e2.而这个是一个常量,符合C标准。
ok,给出一个链接,详细的解释了gcc中##的用法:gcc concatenation