当前位置: 首页 > article >正文

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),运行结果:


http://www.kler.cn/a/560934.html

相关文章:

  • 【安装及调试旧版Chrome + 多版本环境测试全攻略】
  • [特殊字符] Elasticsearch 双剑合璧:HTTP API 与 Java API 实战整合指南
  • 塔能科技构建智慧隧道生态系统——城市升级改造的协同创新典范
  • 【Java项目】基于Spring Boot的简历系统
  • 电脑没声音了怎么恢复正常?一键恢复电脑声音
  • 使 Windows 呈现 macOS 风格的多功能桌面美化软件
  • 连锁管理系统的五大核心设计及 PHP 源码分享
  • 【深度解析:基于 C 语言实现含 IP 城市地址因素的抖音式简化推荐算法】
  • 2.2 STM32F103C8T6最小系统板的四种有关固件的开发方式
  • 超导量子计算机的最新进展:走向实用化的量子革命
  • 官方文档学习TArray数组的运算符
  • GaussDB会话超时参数与最大连接数设置
  • 一文读懂Docker之Docker Swarm集群平台搭建
  • 单片机裸机编程-时机管理
  • 电机控制的空间矢量调制 (SVPWM)
  • ubuntu-24.04.1-desktop 中的 QT6.7 QtCreator 调试程序
  • 数据结构:双链表list
  • elasticsearch在windows上的配置
  • BUUCTF--[极客大挑战 2019]RCE ME
  • 【深度学习】强化学习(RL)-A3C(Asynchronous Advantage Actor-Critic)