为什么在多个标准头文件中声明了特定的C数据类型?

时间:2014-08-15 12:06:30

标签: c dry

例如,C11规定应在以下头文件中声明size_t

  • STDDEF.H
  • stdio.h中
  • stdlib.h中
  • string.h中
  • time.h中
  • uchar.h
  • wchar.h

当读取C11时,我发现在多个标准头文件中声明了许多其他数据类型。

问题

  1. 让我们在size_t的情况下说。为简单起见,为什么不在stddef.h
  2. 假设C编译器在这些头文件中实现size_t。它们是否保证在这些头文件中具有相同的定义?

4 个答案:

答案 0 :(得分:22)

作为stdio.h中声明的要求size_t预先声明的函数的示例,请考虑snprintf()。实际上,如果您想在代码中使用它,您需要做的只是#include <stdio.h>。如果size_t仅在stddef.h中声明,则必须

#include <stddef.h>
#include <stdio.h>

不仅如此,但由于stdio.h声明snprintf无论您是否使用它,您都必须在每时间包含两个文件你需要stdio.h中的任何来避免编译错误; stdio.h会对stddef.h产生人为依赖。这会导致您的源代码变得更长且更脆弱(请注意,如果您颠倒两个指令的顺序,它也会破坏)。相反,我们编写头文件以使它们独立并且不依赖于其他头文件,这就是C标准化委员会为标准库决定的内容。

答案 1 :(得分:10)

  

在size_t的情况下,让我们说。为简单起见,为什么不在stddef.h中?

该类型用于所有这些文件中的函数声明。如果它未在<stdio.h>中声明,除非您首先包含<stddef.h>,否则您将收到编译错误。

  

让我们说C编译器在这些头文件中实现size_t。它们是否保证在这些头文件中具有相同的定义?

是的,他们将有相同的定义。通常,该值在单个位置定义在其他包含文件中。

在某些情况下,可以使用编译器选项或定义来修改定义,例如,允许32/64位编译的编译器可以将size_t定义为32位或64位无符号实体,具体取决于目标在编译器命令行上定义。

答案 2 :(得分:6)

by 之间存在细微差别 - 只需一个实体就可以在单个标头中定义size_t。 #39;在包含指定标题时定义。所以,你有两个选择:

  1. 在每一个中定义size_t并将每个包裹在包含警卫
  2. 将其定义在一个文件中,并将其包含在include guards
  3. 是的,size_t 必须定义为指定的,(glibc):

    typedef unsigned long size_t;
    

    typedef unsigned int size_t
    

    他们并不是说你必须保持理智,他们只是说当任何人包含其中一个标题时需要定义它,因为它们依赖于它被定义并且可以独立使用。简而言之,如果您定义依赖于size_t的内容,则必须首先(先前)定义size_t

    你这样做(或者更确切地说,在哪里)取决于你的实施。

答案 3 :(得分:5)

首先,当一个人执行#include <stdio.h>时,并不要求实际存在任何名为stdio.h的文件,或者编译器对这样的文件执行任何操作。相反,要求是这样的行必须​​使得所有被指定为与<stdio.h>相关联的标识符根据规范来定义。对于编译器而言,#include <stdio.h>只是允许使用硬编码到编译器中的某些标识符,这是完全合法的。因为编译器供应商使事情符合规范要求的最简单方法是让#include <stdio.h>指令通过预处理器运行某个文件stdio.h的文本,这是许多编译器所做的,但是这不是必需的。

当规范列出&#34;文件&#34;应该声明size_t的地方,它真正说的是命名任何一个文件的#include指令应该在全局范围内创建该标识符。这可以通过使具有所有列出的名称的文件包含size_t的定义,或者通过将size_t内置到编译器中但仅启用编译器的内置定义来查看{{{ 1}}指令,带有一个指定的名称。