注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。
测试环境:Ubuntu 10.10
GCC版本:4.4.5
一、#运算符
1)#运算符用于在预处理期将宏参数转换为字符串
2)#的转换作用是在预处理期完成的,因此只在宏定义中有效
3)编译器不知道#的转换作用(预编译期间行为)
4)用法
#define STRING(x) #x
printf("%s", STRING(Hello World!));
打印:Hello World!
实例分析
#运算符的基本用法
25-1.c
#include <stdio.h>
#define STRING(x) #x
int main()
{
printf("%s\n", STRING(Hello World!));
ptintf("%s\n", STRING(100));
printf("%s\n", STRING(while));
printf("%s\n", STRING(return));
return 0;
}
操作:
1)gcc 25-1.c -o 25-1.out编译正确,打印结果:
Hello World!
100
while
return
2)注释掉头文件,预编译:gcc -E 25-1.c -o 25-1.i
# 1 "25-1.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1
# 1 "<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-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;
}
操作:
1)编译:gcc 25-2.c -o 25-2.out编译正确,运行结果:
Cakk function square
result = 16
Call function func
result = 10
2)注释掉头文件,预编译命令:gcc -E 25-2.c -o 25-2.i
# 1 "25-2.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1
# 1 "<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", "fcun"), func(10));
printf("result = %d\n", result);
return 0;
}
二、##运算符
1)##运算符用于在预处理期粘连两个标识符
2)##的连接作用是在预处理期完成的,因此只在宏定义中有效
3)编译器不知道##的连接作用(再次强调和编译期无关)
4)用法
#define CONNECT(a, b) a##b
int CONNECT(a, 1) //int a1;
a1 = 2;
实例分析
##运算符的基本用法
25-3.c
#include <stdio.h>
#define NAME(n) name##n
int main()
{
int NAME(1); //int name1;
int NAME(2); //int name2;
NAME(1) = 1;
NAME(2) = 2;
printf("%d\n", NAME(1)); //1
printf("%d\n", NAME(2)); //2
return 0;
}
操作:
1)编译:gcc 25-3.c -o 25-3.out编译正确,打印结果:
1
2
2)注释掉头文件stdio.h,预编译:gcc -E 25-3.c -o 25-3.i
# 1 "25-3.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1
# 1 "<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;
}
实例分析
##运算符的工程应用
25-4.c
#include <stdio.h>
/*
知识点:typedef、##粘连符
重命名结构体:typedef struct _tag_##type type;
为了方便定义结构体:struct _tag_##type
*/
#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;
}
操作:
1)编译:gcc 25-4.c -o 25-4.out编译正确,打印结果:
s1.name = s1
s1.id = 0
s2.name = s2
s2.id = 1
2)预编译:gcc -E 25-4.c -o 25-4.i
# 1 "25-4.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1
# 1 "<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)#和##运算符只在宏定义中有效