当我们可以使用“外部”标识符时,为什么我们需要 C 中的头文件?

问题描述 投票:0回答:2

我的理解是,在链接时,如果符号是用'extern'关键字声明的,那么编译器不会抱怨没有它的定义。此外,链接器也不会有任何问题,因为它首先会创建符号表,然后会检测到正确的源代码并填充其定义。

构建一个由多个文件组成的没有头文件的程序似乎完全没有问题——如果一个文件中所有不存在的符号都用'extern'声明好。

如果用'extern'关键字就可以检测到其他文件符号的识别,那为什么还要有'header'文件呢?

c compilation linker header
2个回答
1
投票

我的理解是,在链接时,如果用'extern'关键字声明符号,那么编译器不会抱怨没有它的定义。

C 中的

extern
关键字告诉编译器,它所在的声明描述了标识符,但没有定义它们。1 这是编译时的效果,而不是链接时发生的事情。

如果用'extern'关键字就可以检测到其他文件符号的识别,那为什么还要有'header'文件呢?

将声明放在头文件中允许我们将它们包含在多个源文件中,而无需重新键入它们或复制和粘贴它们。这避免了键入错误,并有助于确保在整个程序中对标识符使用相同的声明。此外,最好在定义标识符的源文件中包含声明标识符的头文件,以便编译器在同一编译中看到声明和定义,并在它们不一致时发出警告。

另一个原因是头文件被认为是相关源文件的作者发布的东西,告诉其他程序员源文件提供了什么。在程序员可以在自己的源文件中使用

extern
编写自己的声明之前,必须有人告诉他们这些声明是什么。编写源文件 NiftyLibrary.c 的人可以(并且应该)编写一份手册,列出所有函数的声明(以及这些函数的作用),然后任何使用 NiftyLibrary.c 的人都可以阅读该手册并将必要的声明键入他们的程序。但是如果库作者提供 NiftyLibrary.h 并且其他程序员只包含标题而不是重新输入所有内容,那就更容易了。

脚注

1这是

extern
的功能之一。由于 C 的发展历史,完整的语义很复杂。


1
投票

函数原型确实在 C 标准中定义,因此与其从标准头文件中获取,不如在使用前将它们写入源代码中。相反,头文件还定义了结构、类型和宏,这些结构、类型和宏可能因系统而异或取决于编译器或库配置。对于这些,标准标头是唯一可靠的来源。

例如,经典程序hello.c可以在不包含任何标准头文件的情况下编写为可移植的:

extern int printf(const char *format, ...);

int main(void) {
    printf("Hello world!\n");
    return 0;
}

当然原型必须与实际实现兼容,否则即使编译没有任何错误,运行程序时也会出现未定义的行为。一个兼容的原型是:

  extern int printf(const char format[], ...);

但是将

printf
定义为
extern int printf(const char *format);
是不正确的,即使您从不使用多个字符串参数调用该函数。

反之,如果要用

fopen
打开文件,
FILE
的定义必须来自
<stdio.h>
。同样,如果没有至少一个定义类型
malloc
.
 的标头,则不能声明 
size_t

© www.soinside.com 2019 - 2024. All rights reserved.