赞
踩
用法如下:
用法的意思是:给宏STRING(x) 传一个参数 x,就会被替换为 #x,然后 # 运算符将 x 转换为字符串。也就是说没有双引号的 hello world! 将被转换为 “hello world!”
看段简单的代码,对 # 运算符有个直观的了解,了解 # 运算符的基本用法
// 25-1.c
#include<stdio.h>
#define STRING(x) #x
int main()
{
printf("%s\n", STRING(hello world!));
printf("%s\n", STRING(100));
printf("%s\n", STRING(while));
printf("%s\n", STRING(return));
return 0;
}
编译运行结果如下:
$ gcc 25-1.c -o 25-1
$ ./25-1
hello world!
100
while
return
可以看到在宏定义 #define STRING(x) #x 中,直接将宏参数转换为字符串,也就是将没有双引号的 hello world!,100,while,return 变为字符串 “hello world!”,“100”,“while” 和 “return”
为了更加深入的了解这个过程,我们单步编译一下,只进行预处理,为了避免不必要的信息,将上面代码的第二行 #include<stdio.h> 注释
$ gcc -E 25-1.c -o 25-1.i
打开文件 25-1.i,如下所示:
# 1 "25-1.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "25-1.c" int main() { printf("%s\n", "hello world!"); printf("%s\n", "100"); printf("%s\n", "while"); printf("%s\n", "return"); return 0; }
从预编译过后的文件 25-1.i 可以看出,# 运算符在预处理期将宏参数转换为字符串
看到上面的例子,不禁有个疑问,知道了# 运算符可以在预处理期将宏参数转换为字符串,这有什么用呢?下面通过一个例子来说明 # 运算符的妙用,如果我们想知道调用了什么函数,结果是什么,将函数名和结果打印出来,这该怎么操作呢,下面就看看 # 运算符的妙用吧
// 25-2.c #include<stdio.h> #define CALL(f, p)(printf("Call function %s\n", #f), f(p)) int square(int n) { return n * n; } int func(int x) { return x; } int main() { int result = 0; result = CALL(square, 4); printf("result = %d\n", result); result = CALL(func, 10); printf("result = %d\n", result); return 0; }
定义的宏是个逗号表达式,返回值等于最后一个表达式的值,利用 # 操作符将函数名转换为字符串,再调用这个函数,计算结果。
编译运行结果如下:
$ gcc 25-2.c -o 25-2
$ ./25-2
Call function square
result = 16
Call function func
result = 10
为了更详细的了解这个过程,同样注释第二行 #include<stdio.h>,单步编译,只进行预处理
$ gcc -E 25-2.c -o 25-2.i
打开文件 25-2.i,如下所示:
# 1 "25-2.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "25-2.c" int square(int n) { return n * n; } int func(int x) { return x; } int main() { int result = 0; result = (printf("Call function %s\n", "square"), square(4)); printf("result = %d\n", result); result = (printf("Call function %s\n", "func"), func(10)); printf("result = %d\n", result); return 0; }
用法如下:
## 运算符将两个标识符连接成一个标识符,a##b 就变成了 ab,所以 a##1 就相当于 a1
下面通过一个实例了解 ## 运算符的基本用法,直接看代码
// 25-3.c
#include<stdio.h>
#define NAME(n) name##n
int main()
{
int NAME(1);
int NAME(2);
NAME(1) = 1;
NAME(2) = 2;
printf("%d\n", NAME(1));
printf("%d\n", NAME(2));
return 0;
}
宏定义 #define NAME(n) name##n,表示连接 name 和 n,使之变为一个标示符 namen,所以 int NAME(1) 被宏替换为 name1,int NAME(2) 被宏替换为 name2
真的是和我们分析的一样吗,我们编译运行一下:
$ gcc 25-3.c -o 25-3
$ ./25-3
1
2
我们再单步编译一下,只进行预编译,查看预编译之后的代码,同样为了避免不必要的信息,将程序第二行注释。
$ gcc -E 25-3.c -o 25-3.i
打开文件 25-3.i,如下所示,和我们分析的完全一致
# 1 "25-3.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "25-3.c" int main() { int name1; int name2; name1 = 1; name2 = 2; printf("%d\n", name1); printf("%d\n", name2); return 0; }
下面我们看一个 ## 运算符在工程中的应用
如果我们要定义一个结构体,因该怎么定义呢,很简单,定义如下:
#include<stdio.h>
struct Student
{
char* name;
int id;
};
int main()
{
struct Student s;
s.name = "s1";
s.id = 0;
return 0;
}
我们可能会定义很多变量,每次定义一个变量前面都要加 struct,这很麻烦,能不能不写呢,当然可以,使用 typedef 就可以了,代码如下:
#include<stdio.h>
typedef struct _tag_Student Student;
struct _tag_Student
{
char* name;
int id;
};
int main()
{
Student s;
s.name = "s1";
s.id = 0;
return 0;
}
这样在定义变量的时候直接使用结构体名字 Student 就可以了,不用再写 struct,但是还不够完美,因为在定义结构体的时候还是需要写 struct,如果定义很多结构体,那岂不是要重复写很多遍,有没有办法不写呢,## 运算符的作用就来了。
// 25-4.c #include<stdio.h> #define STRUCT(type) typedef struct _tag_##type type;\ struct _tag_##type STRUCT(Student) { char* name; int id; }; int main() { Student s1; Student s2; s1.name = "s1"; s1.id = 0; s2.name = "s2"; s2.id = 1; printf("s1.name = %s\n", s1.name); printf("s1.id = %d\n", s1.id); printf("s2.name = %s\n", s2.name); printf("s2.id = %d\n", s2.id); return 0; }
上面的代码中,type 是结构体的名字,## 运算符连接 _tag_ 和 type 变为 _tag_type,这不就是我们前面定义的结构体吗,struct _tag_##type 可以看作 struct _tag_type
编译运行一下:
$ gcc 25-4.c -o 25-4
$ ./25-4
s1.name = s1
s1.id = 0
s2.name = s2
s2.id = 1
看了上面的过程可能还是有点蒙,下面将第二行 #include<stdio.h> 注释,单步编译,只进行预处理,看一下预处理之后的代码
$ gcc -E 25-4.c -o 25-4.i
打开文件 25-4.i,如下所示:
# 1 "25-4.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "25-4.c" typedef struct _tag_Student Student; struct _tag_Student { char* name; int id; }; int main() { Student s1; Student s2; s1.name = "s1"; s1.id = 0; s2.name = "s2"; s2.id = 1; printf("s1.name = %s\n", s1.name); printf("s1.id = %d\n", s1.id); printf("s2.name = %s\n", s2.name); printf("s2.id = %d\n", s2.id); return 0; }
这不就是我们之前写的代码吗,只不过通过 ## 标识符,使我们写起来更加简单了。
1、# 运算符用于预处理期将宏参数转换为字符串
2、## 运算符用于预处理期粘连两个标识符
3、编译器不知道 # 和 ## 运算符的存在
4、# 和 ## 运算符只在宏定义中有效
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。