95.【C语言】解析预处理(3)
目录
1.#和##
0.前置知识:字符串的合并
1.#
PRINT宏的设计
2.##
应用1:批量定义变量
应用2:批量定义函数
2.命名约定
3.undef
4.命令行定义
应用:为数组开辟合适的空间
承接94.【C语言】解析预处理(2)文章
1.#和##
0.前置知识:字符串的合并
#include <stdio.h>
int main()
{
printf("Hello World!\n");
printf("Hello"" World!\n");
return 0;
}
运行结果
printf("Hello World!");与printf("Hello"" World!");的打印结果是等价的
printf("Hello"" World!");将"Hello"和" World!"两个字符串合并,这点可以通过反汇编代码看出,如下:
注意:不能写成printf("Hello"," World!");中间参数不能有逗号,原因:printf在没有%占位符的情况下只能传入一个参数
1.#
作用:将宏的一个参数转换为字符串字面量
例如:设计一个PRINT宏,完成以下任务:
int a = 1;
float f = 1.1f;
double d = 3.14;
_Bool b = 1;
PRINT(a, %d);
PRINT(f, %f);
PRINT(d, %lf);
PRINT(b, %d);
输出结果:
PRINT宏的设计
观察发现:PRINT宏要传两个参数,因此应该设计成类似#define PRINT(val,format) ??????的样子,其中val为变量,format为val输出的格式
如果设计成下面这样会有问题:
#define PRINT(val,format) printf("the value of val is format\n",val)
VS编译器会报警告:
而且打印的结果也会有问题:
显然format是按字符串打印的并没有被替换为val变量输出的格式,这就要引入#运算符,写法如下
#define PRINT(val,format) printf("the value of "#val" is "#format"\n",val)
"将宏的一个参数转换为字符串字面量"简单来说,就是将参数变化成对应的字符串(即字符串化)
例如当val传a的时候,"#val"等价为""a"",可以使用Linux环境下的gcc编译器,只执行预处理
将以下代码写入test.c中
#include <stdio.h>
#define PRINT(val,format) printf("the value of "#val" is "#format"\n",val)
int main()
{
int a = 1;
float f = 1.1f;
double d = 3.14;
_Bool b = 1;
PRINT(a, %d);
PRINT(f, %f);
PRINT(d, %lf);
PRINT(b, %d);
return 0;
}
使用以下命令只执行预处理:
gcc -E test.c -o test.i
查看test.i文件:
2.##
作用:把位于它两边的符号合成一个符号,简称记号粘合
应用1:批量定义变量
#define STUDENT(num) int Student##num=1
int main()
{
STUDENT(1);
STUDENT(2);
STUDENT(3);
STUDENT(4);
STUDENT(5);
return 0;
}
STUDENT(num)的作用:按学生的编号num,批量初始化不同学生的初始值
Linux生成的i文件为:
应用2:批量定义函数
例如求两个变量的较大值,变量的类型可能为int、float、double和char等等
#define TYPE_MAX(type) \
type type_max(type x,type y)\
{\
return x > y ? x : y; \
}
TYPE_MAX(int)
TYPE_MAX(float)
TYPE_MAX(double)
TYPE_MAX(char)
int main()
{
return 0;
}
注意TYPE_MAX(?)结尾不要写分号!
Linux生成的i文件为:
2.命名约定
即1.把宏名全部大写 2.函数名不要全部大写
其实宏也存在小写的情况:例如offsetof宏(返回结构体成员的偏移量)全小写
(来自https://legacy.cplusplus.com/reference/cstddef/offsetof/)
3.undef
如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除(使用#undef 旧名字)
undef的全称undefined
方法:先解除旧名字,再对其设置新的值或者不做任何操作(即不再设置新的值)
#include <stdio.h>
#define NUM 1
int main()
{
printf("%d\n", NUM);
#undef NUM
#define NUM 2
printf("%d\n", NUM);
return 0;
}
运行结果:
4.命令行定义
应用:为数组开辟合适的空间
例如:不同的机器的运行内存有大有小,因此需要指定合适的空间提供给数组,如下:
#include <stdio.h>
int main()
{
int arr[capacity];
for (int i = 0; i < capacity; i++)
{
arr[i] = i;
printf("%d", arr[i]);
}
return 0;
}
直接编译肯定会报错,需要为capacity指定值,Linux下使用以下命令:
gcc test.c -o test.o -D capacity=指定的值
例如capacity取10(其实预处理阶段将capacity替换为10),运行结果: