编译预处理
# 开头的是编译预处理指令,编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值,这是完全的文本替换
#define <名字> <值>
注意没有结尾的分号,因为不是 C 的语句。名字必须是⼀个单词,值可以是各种东西。
如果一个宏的值中有其他的宏的名字,也是会被替换的
#define PI 3.14
#define PI2 2*PI
如果一个宏的值超过一行,最后一行之前的行末需要加 \
#define PRT printf("Hello"); \
printf("World")
宏的值后面出现的注释不会被当作宏的值的一部分
#define PI 3.14 // 定义圆周率
常用语法
下面是常用的几个宏指令,它们可以直接在代码中使用
#if // 如果表达式为真,执行代码
#else // 如果 #if 表达式为假,执行代码
#elif // 相当于 else if
#endif // 用来标志一个条件指令的结束
#ifedf // 如果本指令所引用的定义已存在,执行代码
#ifndef // 如果本指令所引用的定义不存在,执行代码
#include // 一个编译预处理指令,和宏一样,在编译之前就处理了,它把那个文件的全部文本内容原封不动地插入到它所在的地方
#undef // 取消宏定义
为了防止重复包含头文件,常在文件头尾添加宏定义
#ifndef LOVE_FISHC
#define LOVE_FISHC
class FishC {...};
#endif
建议使用文件名作为宏名,例如对 math.h
#define __MATH_H
也可以使用
#pragma once
防止整个文件内容被重复包含(可能有兼容性问题)
在头文件中定义变量时,不仅要用编译预处理指令判断引用,最好还要使用 static const 来避免重复定义
特殊的宏
__cplusplus // 该宏在 C++ 文件中自动生成,表示这是 C++ 文件
__FILE__ // 当前文件名字符串
__LINE__ // 当前行号整型
__DATE__ // 日期字符串
__func__
__FUNCTION__ // 两者都表示当前执行的函数名字符串
__TIME__ // 时间字符串
例如我们可以输出当前函数名
printf("%s", __func__);
可以修改行号和原文件名
#line 行号 ["文件名"]
例如有时我们希望调整下一行的行号
#include <stdio.h>
#line 100 "macro-new.c" // 更改下一行的行号和源文件名
int main() // line 100
{
printf("%d\n", __LINE__); // line 102
printf("%d\n", __LINE__); // line 103
printf("%s\n", __FILE__);
return 0;
}
带参数的宏
使用宏可以简化一些函数的书写
#define F(x) ((x)*(x)*(x))
printf(“%d”,F(5));
需要注意,宏是单纯的文本替换,因此
- ⼀切都要括号
- 整个值要括号
- 参数出现的每个地方都要括号

浙公网安备 33010602011771号