我知道
extern
的一些基本用法,但有一件事确实困扰着我。如果真的如图所示,为什么下面两段代码不一样?
#include <stdio.h>
int i;
int main() {
printf("i = %d\n", i);
return 0;
}
#include <stdio.h>
extern int i;
int main() {
printf("i = %d\n", i);
return 0;
}
另外,下面的代码会有警告:
警告:“i”已初始化并声明为“extern”
为什么?
extern int i = 0;
谁能告诉我
extern
到底是怎么回事?
图像中的文本是错误的,因为“extern”和“auto”不是存储类。
extern
和auto
是C语法中的存储类关键字,但C链接的类型是external、internal和none,存储类的类型是static、thread 、自动和分配。这种区别很重要,因为存储类关键字不仅仅与存储类或链接相关;它还与存储类关键字相关。它们因 C 开发的历史而变得复杂。
在文件范围内,
int i;
是名为 i
的对象的临时定义。尽管有它的名字,“暂定定义”并不是一个定义(就像工作面试中的潜在雇员不是雇员一样)。如果翻译单元中不存在常规定义,则暂定定义将导致创建定义。然而,由于不同的 C 实现对
int i;
的处理方式不同,C 标准没有定义如果有多个定义会发生什么。一些 C 实现将兼容的临时定义产生的多个定义合并为单个定义。有些人将它们视为错误。 GCC 版本 10 中的默认值已更改。在文件范围内,extern int i;
是名为
i
的对象的 声明,该对象不是定义。它不会为 i
保留存储空间,并且,如果在程序中使用 i
,则必须在程序的其他位置对其进行定义。在文件范围内,extern int i = 0;
是名为
i
的对象的 定义。根据 C 标准的规则,带有初始化的声明也是一个定义,即使它有 extern
,因此编译器应该将其视为定义。然而,C 用户的惯例是使用 extern
来区分不是定义的声明。因此,用 int i
声明 extern
并用 = 0
提供初始化违反了该约定。但该约定不是 C 的规则。因此编译器会警告这种违反约定的行为,但符合 C 标准的编译器必须接受此代码作为 i
的定义。 (如果您将警告变成错误,就像 Clang 或 GCC 中的 -Werror
开关一样,编译器不接受此代码并成为不合格编译器。)