C语言#include还有些你不知道的事

💡 原文中文,约1700字,阅读约需4分钟。
📝

内容提要

#include指令在C语言中用于插入头文件内容,有两种形式:使用<>包含标准库头文件,使用""包含自己程序开发的源文件。可以使用宏和条件式编译避免多次包含。不能将#include指令放在extern "C"内部。可以包含.c文件,但不常见。

🔎

延伸解读

两种包含形式的搜索路径差异

文章指出,#include <xxx.h> 和 #include "xxx.h" 的主要区别在于搜索路径。使用双引号时,预处理器会先搜索当前目录或项目目录,再搜索标准包含路径;而使用尖括号时,直接搜索标准包含路径。因此,包含自定义头文件时用双引号效率更高,因为减少了不必要的路径查找。

嵌套包含与重复包含的隐患

预处理器允许最多15层嵌套包含,这可能导致同一个头文件被多次包含。例如,blinky.c 直接包含 stdio.h,而 blinky.h 也包含 stdio.h,当 blinky.c 包含 blinky.h 时,stdio.h 就会被间接包含两次。重复包含可能引发重定义错误,因此需要采取措施避免。

条件编译防止重复包含

为避免头文件被多次包含,常用条件编译指令。在头文件中使用 #ifndef 检查唯一标识符(如 BLINKY_H_),若未定义则定义它并包含内容。这样,当头文件再次被包含时,预处理器会跳过内容,防止重复定义。这是 C 语言中管理头文件的常见做法。

包含 .c 文件的可行性及风险

从语法上讲,#include 可以包含 .c 文件,编译器能正常处理。但通常不推荐,因为 .h 文件提供接口,.c 文件提供实现,且不一一对应。如果 .c 文件包含其他模块的 .h 文件,可能因结构、变量等重复定义而导致错误。因此,包含 .c 文件虽可行,但实践中很少使用。

❓

Q&A

#include "xxx.h" 和 #include <xxx.h> 有什么区别?

两者都是预处理指令,用于插入头文件内容。区别在于搜索路径:使用 <> 时,预处理器在标准 include 路径中搜索;使用 "" 时,搜索路径包含了 <> 的搜索路径,因此效率更高。通常,<> 用于包含标准库头文件,"" 用于包含自己程序开发的源文件。

如何避免头文件被多次包含?

可以使用条件编译。在头文件中用 #define 定义一个唯一的标识符(如 BLINKY_H_),然后用 #ifndef 检查该标识符是否已定义。如果未定义,则定义它并包含头文件内容;如果已定义,则跳过,从而避免重复包含。

#include 嵌套包含最多支持多少层?

预处理器最多允许 15 层的嵌套包含。

为什么不能把 #include 指令放在 extern "C" { ... } 里面?

文章指出不能将 #include 指令放置在 extern "C" { ... } 内部,并提供了参考链接说明原因,但未展开具体解释。

C语言中 #include 可以包含 .c 文件吗?

可以。从语法角度讲,include 的意思就是从当前位置包含另外一个文件,因此包含 .c 文件是可行的,C 编译器能够正常处理。但一般不常见,因为 .h 文件提供接口,.c 文件提供实现,如果包含 .c 文件可能导致结构、变量等重复定义而出错。

#include 命令中可以使用宏吗?

可以。例如可以根据 _DEBUG_ 是否定义来确定包含哪些头文件,但需要注意可能引起重复包含的问题。

🏷️

标签

➡️

继续阅读