当前位置:网站首页>【C语言】预处理操作
【C语言】预处理操作
2022-07-31 03:00:00 【Ahao_te】
在编译一个C语言涉及很多步骤。其中第一个步骤就是预处理阶段。
1、预处理详解
1.1、预定义符号
下面这章表总结了由预处理器定义的符号。它们的值或者是字符串常量,或者是十进制数字常量。__ FILE __ 和 __ LINE __ 分别用于查看文件的磁盘地址和源文件代码行号,__ DATE __ 和 __ TIME 分别代表日期和时间, STDC __ 辨别编译器是否遵循ANSI C。
具体展示:
#include<stdio.h>
int main()
{
int i = 0;
FILE* pf = fopen("log.txt", "w");
if (pf == NULL)
{
perror("fopen");
return -1;
}
for (i = 0; i < 10; i++)
{
fprintf(pf, "file:%s line=%d date:%s time:%s i=%d\n", __FILE__, __LINE__, __DATE__, __TIME__, i);
}
fclose(pf);
pf = NULL;
return 0;
}
1.2、#define
1.2.1 #define 定义标识符
#define name stuff
比如
#define MAX 1000
//如果是 #define MAX 1000;
//max = 1000;; 不太合适
if(condition)
max = MAX;
else
max = 0;
1.2.2 #define 定义宏
#define 机制有一个规则,运行把参数替换到文本中,这种实现被称为宏或者定义宏。
下面是宏的声明方式:
#define name( parament-list ) stuff
其中parament-list 是一个由逗号分隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧贴。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
下面看宏的替换
比如有一个
#define SQUARE( x ) x*x
SQUARE(5);将会等于55,那么如果是SQUARE(5 + 1),就会等于5 + 1 * 5 +1。
这就比较清晰的提醒我们,进行宏定义的时候,最好是别省括号。
比如x * x写成 ((x)(x)),这样能使我们更准确的得到预期效果。
1.2.3 #define 替换规则
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后再看看是否还有其它的#define定义的符号。如果是就重复1,2步骤。
注意:
- 宏参数和#define 定义中可以出现其它#define 定义的符号。但是对于宏,不能出现递归。
- 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
1.2.4 #和##
如何把参数插入到字符串中?
char* p ="hello ""world\n";
printf("hello," world\n);
printf("%s",p);
这里输出的是不是
hello world?
是,我们发现字符串是有自动连接的特点的。
当字符串作为宏参数的时候想做为字符串放入字符串中。
用# ,把一个宏参数变成对于的字符串。
也就是下面这个情况
将i+3作为参数传给VALUE,并且通过#将参数原本的内容作为一个字符串放入字符串。
int i = 10;
#define PRINT(FORMAT, VALUE)\ printf("the value of " #VALUE " is "FORMAT "\n", VALUE);
...
PRINT("%d", i+3); //产生什么效果?
##的作用
##能将两边的符号合成一个符号
注意:
这样的连接必须产生一个合法的标识符。否则结果就是未定义的。
#define CAT(str, Num) str##Num
int main()
{
char* str1 = "hello world";
printf("%s\n", CAT(str, 1)); //"hello world"
printf("%s\n", str1); //"hello world"
return 0;
}
1.2.4 带副作用的宏参数
x+1; 不带副作用的
x++; 带副作用的
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);
输出结果:6,10,9。
1.2.4 宏和函数对比
宏通常被应用与执行简单的运算。
比如在需要一些简单的加减乘除操作,宏的优秀性就比较突出。
因为:
- 宏比函数在程序的规模和速度方面更胜一筹
- 宏与类型无关
但是宏也有缺点
- 每次使用宏的时候,需要将宏定义的代码插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
- 宏是无法调试的。
- 宏因为和类型无关,所以不够严谨
- 宏可能会带来优先级的问题,容易使得程序出错。
1.2.4 命名约定
宏名全部大写
函数名不要全部大写
1.3 #undef
#undef NAME
用于移除一个宏定义
1.4 条件编译指令
当有些调试性的代码,删除可以,保留又碍事,所以我们可以选择性的编译。
比如:
#define __DEBUG__
int main()
{
int i = 0;
int arr[10] = {
0 };
for (i = 0; i < 10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("%d\n", arr[i]);
#endif //__DEBUG__
}
return 0;
}
还有其它的常见条件编译指令:
#define M 6
int main()
{
#if M<5
printf("haha\n");
#elif M==5
printf("heihei\n");
#else
printf("hey!\n");
#endif
return 0;
}
ifndef == if not define
ifdef == if define
#define MAX 100
int main()
{
#ifndef MAX //#indef MAX
printf("max\n");
#endif
return 0;
}
1.5 实现OFFSETOF
宏定义offsetof是用来观察结构体成员的偏移地址的。
offsetof(type, m_name)
比如
#include <stddef.h>
struct S
{
char c1;
int a;
short c2;
char c3;
};
int main()
{
struct S s = {
0 };
printf("%d\n", offsetof(struct S, c1));
printf("%d\n", offsetof(struct S, a));
printf("%d\n", offsetof(struct S, c2));
printf("%d\n", offsetof(struct S, c3));
}
从地址为0的位置访问结构体成员,就能得到对应的地址以及相等的偏移量。
struct S
{
char c1;
int a;
short c2;
char c3;
};
#define OFFSETOF(type,name) (int)&(((type*)0)->name)
int main()
{
struct S s = {
0 };
printf("%d %d %d %d",OFFSETOF(struct S, c1), OFFSETOF(struct S, a),
OFFSETOF(struct S, c2), OFFSETOF(struct S, c3));
return 0;
}
本章完
边栏推荐
- Unity3D Button mouse hover enter and mouse hover exit button events
- CMOS和TTL的区别?
- Multilingual settings of php website (IP address distinguishes domestic and foreign)
- MultipartFile文件上传
- SQL注入 Less54(限制次数的SQL注入+union注入)
- The use of font compression artifact font-spider
- Map.Entry理解和应用
- 加密公司向盗窃的黑客提供报价:保留一点,把剩下的归还
- Chapter 9 SVM实践
- Discourse Custom Header Links
猜你喜欢
随机推荐
【C语言】进制转换一般方法
LeetCode Daily Question 2022/7/25-2022/7/31
Chapter 9 SVM Practice
【HCIP】ISIS
关于 mysql8.0数据库中主键位id,使用replace插入id为0时,实际id插入后自增导致数据重复插入 的解决方法
STM32问题合集
The simulation application of common mode inductance is here, full of dry goods for everyone
Mysql 45讲学习笔记(二十五)MYSQL保证高可用
AtCoder Beginner Contest 261 Partial Solution
php 网站的多语言设置(IP地址区分国内国外)
Basic learning about Redis related content
Android's webview cache related knowledge collection
10、Redis实现点赞(Set)和获取总点赞数
编译Hudi
SQL injection Less54 (limited number of SQL injection + union injection)
The application of AI in the whole process of medical imaging equipment
Software accumulation -- Screenshot software ScreenToGif
观察者模式
【C语言】求两个整数m和n的最大公因数和最小公倍数之和一般方法,经典解法
CentOS7下mysql5.7.37的卸载【完美方案】