C语言中关于宏 ##的使用,注意一点

文章转自: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

猜你喜欢

转载自blog.csdn.net/ATOOHOO/article/details/88935129
今日推荐