C-我应该在一个单独的目录中使用引号或括号来包含标题吗



我有一个包含srcinclude目录的项目。编译时,我通过-I选项(gcc -Iinclude ...)传递include目录。

我应该使用双引号(")还是尖括号(<)来包含我自己的头文件?


我试图寻找答案,发现这两种相互矛盾的说法:

  1. 通过双引号包含相对于c文件的头文件。所有其他内容(包含路径中的头文件)都带有尖括号。->因此使用尖括号
  2. 包括带尖括号的标准标题。其他都用双引号->因此使用双引号

在我看来,陈述2更清楚。当包含一个带有双引号的文件时,最明显的是它是我自己的头。


我应该使用引号或括号来包含我自己的头文件吗?C标准允许这两种可能性。那么,最佳实践是什么呢?

常见的约定是:

  • 对于属于C实现或平台的头文件,请使用< … >——项目之外的头文件(如C标准库、Unix或Windows头文件),以及通常为开发环境安装的库的头文件
  • 对于属于项目一部分的标题,请使用" … "

这不是完全由C标准决定的;这是一般做法的问题。对于每个分隔符选择,编译器都有一个查找标头的位置列表(搜索路径)。这些搜索路径通常是为了方便上述使用而设计的,但它们可以通过命令行开关、环境变量、系统设置和/或构建编译器时的设置进行自定义(取决于您使用的编译器)。

以下是C标准在C 2018 6.10.2中对它们的说明。第2段说:

表单的预处理指令

#include<h-char-序列>new-line

在实现定义的位置序列中搜索由<>分隔符之间的指定序列唯一标识的报头,并使该指令被报头的整个内容替换。如何指定位置或标识标头是实现定义的。

第3段说:

表单的预处理指令

#include"q-char-序列"新品

导致用源文件的全部内容替换该指令,该源文件由";分隔符。以实现定义的方式搜索命名的源文件。如果不支持此搜索,或者搜索失败,则指令将被重新处理,如同读取一样

#include<h-char-序列>新品

具有与原始指令相同的包含序列(包括>字符,如果有的话)。

注意两者之间的一些差异:

  • 括号形式的文本表示它搜索唯一标识为的页眉。引用表单的文本中不包含单词"unique"。这表明方括号形式引用的所有标题都应该彼此不同,如果它们是旨在避免歧义的设计系统的一部分,你可能会想到这一点
  • 注意,它说第一个表单"搜索一系列实现定义的位置"。这与编译器有一个搜索标准头的位置列表相一致。对于第二种形式,它使用"由指定序列标识的源文件"。这与在文件系统中使用引号之间的文本作为路径一致

标准中的这段文本非常宽松,都允许使用实现定义的方法来识别文件,因此可以将其中一种扩展为与另一种相同(尽管看到编译器抱怨括号中的头不是唯一的会很有趣),并且编译器配置选项足够广泛,您可以在项目中使用每种方法。然而,一般来说,还是坚持惯例为好。

考虑这个例子:

+- include/
|  |
|  - header.h
|
+- src/
|
- main.c

声明中说,要么使用:

#include "../include/header.h"
gcc src/main.c

或:

#include <header.h>
gcc -Iinclude src/main.c

您可以决定使用哪种样式。我个人更喜欢第二个。但更重要的是在整个项目中使用一致的风格。

问题中的第一句话符合当前版本的C++核心指南的规则SF.12

相对于include文件,文件更喜欢#include的引号形式,其他地方都是角括号形式

尽管它与C++23标准15.3注1(草案N4928)的建议相冲突:

使用< >形式作为实现提供的头,使用" "形式作为实现控制之外的源,实现了更广泛的可移植性

我建议您应用SF.12,因为它可以降低包含错误文件的风险,正如他们所解释的:

如果不遵守这一点,将导致难以诊断错误,因为在包含文件时错误地指定了范围,从而拾取了错误的文件。例如,在典型的[编译器实现]中,#include ""搜索算法可能首先搜索存在于本地相对路径的文件,然后使用这种形式来引用非本地相对的文件可能意味着,如果文件在本地相对路径上出现(例如,包括的文件被移到新位置),它现在将在上一个include文件之前被找到,并且include集将以意外的方式被更改。

如果使用< >,则不会搜索相对于包含文件的路径(对于典型的编译器实现),因此上述情况不会成为问题。

或者更一般地说:如果编译器实现找到具有两种形式的文件,请使用不太可能产生歧义的形式。由于< >" "的后备(根据标准)," "将搜索潜在的更多位置。因此,尽可能使用< >

尽管共同的惯例不同。SF.12提供了稍微偏离该公约的技术理由。

最新更新