【The Cherno 头文件】Include Guard 和
先说结论:Include Guard是基于宏的,而#pragma once是基于文件的。
乍一看,这两个没什么区别,都是为了防止头文件的内容被同一个编译单元包含两次而使用。
但硬要说区别的话就是上面的结论。
- 实验文件:
main.c、header1.h、header2.h - 实验命令:
gcc -E main.c -o main.i,得到预编译文件 - 实验目的:观察
header2.h中header2_1()函数与header2_2()函数的包含次数
1 | /* main.c */ |
目的非常简单,就是要看结果会包含两个头文件header1.h和header2.h的哪些内容。
1 | /* header1.h */ |
1 | /* header2.h */ |
Step1 正常情况
1 | # 0 "Main.c" |
可以发现header2.h被包含了两次。这会导致重定义问题
接下来直接展示Include Guard 和 #pragma once 的区别。
对header2.h做具体修改(重复包含保护)
Step2 Include Guard
1 | /* header2.h */ |
- 注意我只对
header2_2()做了保护
然后预处理得到结果
1 | # 0 "Main.c" |
可以发现header2_1()被重复包含了。毕竟我只对header2_2()部分做了保护
Step3 #pragma once
1 | /* header2.h */ |
- 注意预编译指令的位置
然后预处理得到结果
1 | # 0 "Main.c" |
可以发现整个header2.h只被包含了一次。
原理分析
Include Guard
预编译器在碰到#ifndef后就会检查宏表是否有相应的宏定义
如果有,就会掠过#ifndef和#endif所包含的内容,预编译#endif后面的内容。
#pragma once
预编译器在碰到#pragma once就会标记当前文件,比如本实验中就是header2.h
这样预编译器下一次在别的文件中再次执行#include "header2.h"就会直接跳过不执行。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 星の夜!
