C 标准库中的头文件可以包含另一个头文件吗?

Posted

技术标签:

【中文标题】C 标准库中的头文件可以包含另一个头文件吗?【英文标题】:May a header from the C standard library include another header? 【发布时间】:2021-04-28 07:30:43 【问题描述】:

我依稀记得一条规则,“C 标准库的标头不得包含 C 标准库的任何其他标头,除非特别允许”。但奇怪的是,我在 C11 中找不到这样的规则。我本来希望它出现在 7.1.2“标准标题”中。

C 中有这样的规则吗? POSIX 中有这样的规则吗? 其他标准中是否有这样的规则?

【问题讨论】:

我不认为这可以作为一个规则应用,而是作为一个建议,但是是的,很多论文都提到了这一点:即:规则#7。每个头文件 A.h 都应该 #include 所有其他 A.h 需要正确编译的头文件,但仅此而已。 A.h 中需要什么:如果另一个结构类型 X 用作结构类型 A 的成员变量,那么您必须在 A.h 中 #includeX.h 以便编译器知道 X 成员有多大。不要包含只有 .c 文件代码需要的头文件。 – #将其包含在 .c 文件中,而不是 .h 文件中。 我个人从来没有理解过这个规则,标准头包括其他标准库头。 @DavidRanieri,你引用的风格推荐——我订阅了——似乎不是 OP 所要求的,而是它的双重性。 【参考方案1】:

据我所知,没有明确说明允许(或不允许)。但我相信下面这段话暗示了这种可能性

7.1.2 标准标题(强调我的)

4 如果使用,标题应包含在任何外部声明或定义之外,并且应首先包含在对其声明的任何函数或对象的第一次引用之前,或到它定义的任何类型或宏。

当我们将这个“应该”要求与一致性部分中的含义进行交叉引用时

4.一致性

2 如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”一词或省略任何明确的行为定义来表示。这三者在重点上没有区别;它们都描述了“未定义的行为”。

因此,如果要调用 abs 函数而不包括 stdlib.h,则行为将是未定义的。本质上未定义的行为包括事物“工作”的可能性。因此,如果另一个标准标头包含 stdlib.h 并且程序“有效”,则这符合上述合同。

【讨论】:

他不是在问什么是头文件以及为什么拥有函数原型是好的。他在问为什么标准库头文件不应该包含其他 SL 头文件 @0___________ - 不,他是在询问标准中是否存在包含 other 标头在内的标准库标头规则(反对)。我就其允许的原因进行了辩护。我没有什么是标头或为什么原型很好(坦率地说,我很困惑你这么理解它)。【参考方案2】:

搜索从 Ansi-C (C90) 到最新草案的 C 标准,并进一步浏览历史参考资料,例如 Unix V7 手册和 K&R 书籍,我找不到该规则的参考资料。

标准头文件的内容、位置和实现是特定于实现的,一些类型和宏定义在多个头文件中,因此需要一个一致的方案来避免重新定义警告,并且在常见的 C 库实现中通过条件包含来实现。

某些系统标头被明确指定为包括其他标头:

7.25 类型泛型数学<tgmath.h>

标头<tgmath.h> 包括标头<math.h><complex.h>,并定义了几个类型通用的宏。

7.26 线程 <threads.h>7.26.1 简介 标头<threads.h> 包括标头<time.h>,定义宏,并声明支持多线程执行的类型、枚举常量和函数。

一些标准 POSIX 标头也被记录为包括其他系统标头。

除非程序员正在实现 C 库,否则该规则不会产生任何影响:记录为定义标准类型、枚举常量、宏、函数或变量的系统头文件应在使用此标识符之前包含在内。系统标头可以按任意顺序包含,多次包含应该不会造成任何问题。

【讨论】:

【参考方案3】:

我依稀记得一条规则“C 标准库没有头文件” 应包括 C 标准库的任何其他头文件,除非 特别允许”。

C 语言规范或 POSIX 标准中没有这样的规则。这两者,尤其是第一个,都避免指定诸如此类的实现细节。它们描述了用户可以依赖的积极结构和语义,但通常不会限制实现以避免特定的结构或细节。

在大多数情况下,标准也没有指定任何特定的标头确实包含其他标头,因此,就样式和可移植性而言,编写代码就像没有标准一样是明智的标头包括任何其他。更一般地说,这导致了一个共同的风格指导,即您编写的每个源文件(包括标头)都应该针对使用的每个标识符适当地声明该标识符本身或 #include 一个记录在案的标头来声明它。

然而,正如@chqrlie 在their answer 中指出的那样,该标准明确规定某些标准库头文件包含特定的其他标准库头文件。

但奇怪的是,我找不到这样的规则 写在 C11 中。我会在 7.1.2“标准”中期待它 标题”。

这确实是人们在 C11 中看到的地方。正如你所说,它没有表达任何具有你描述的效果的规则。

Is there such a rule in C?

不,这将与上述其他规定不一致。此外,在一些假定符合 C 的实现中,标准头文件比@chqrlie 指出的更多 do #include 其他标准库头文件。

Is there such a rule in POSIX?

不,这将与上述其他规定不一致。此外,在一些假定符合 POSIX 的 C 实现中,标准头文件比 @chqrlie 指出的更多标准头文件do #include 其他标准库头文件。

Is there such a rule in any other standard?

我不知道任何其他与 C 标准库相关的标准。代码约定种类繁多,可以想象一个或多个关于编写程序和库头的规则,但标准库不在此类约定的范围内。然而,显然,没有人可以权威地谈论所有标准的世界。

提出 C11 的第 7.1.2/4 段可能也是相关的,其中部分内容是:

标准标题可以按任何顺序包含;每个都可能包括在内 在给定的范围内不止一次,没有任何不同的效果 仅包含一次,除了 [关于 assert.h 的警告; ...]。但是,如果一个标识符被声明或定义在多于 一个标头,第二个和随后的相关标头可能是 包含在对标识符的初始引用之后。

C 语言规范明确拒绝将标准库头文件实现为用 C 语言表示的普通源文件的任何要求,但请注意,在特定实现提供这种表示的范围内,这明确提出了以下可能性:某些标识符可能由多个标头声明或定义。虽然不能保证一定会发生,而且还有其他可能出现的方式,但它与某些标头(包括其他标头)是一致的。

【讨论】:

以上是关于C 标准库中的头文件可以包含另一个头文件吗?的主要内容,如果未能解决你的问题,请参考以下文章

将头文件中的 typedef 枚举包含在另一个头文件中

c++关于multiset的头文件包含问题。

WINDOWS操作系统下的C语言头文件存放在哪个目录中?

CString类型要包含啥头文件

C++中头文件<ctime>包含哪些函数

C/C++ 头文件中各包含哪些函数