c - 为什么显式 "extern"不为对象分配存储?

标签 c language-lawyer declaration definition extern

我一直在深入研究 C 标准,我对它谈论链接和暂定定义的方式感到困惑。
一、在this该标准的一部分指出

extern (keyword) means static duration and external linkage (unless already declared internal)


static storage duration. The storage duration is the entire execution of the program, and the value stored in the object is initialized only once, prior to main function. All objects declared static and all objects with either internal or external linkage that aren't declared _Thread_local (since C11) have this storage duration.


external linkage. The identifier can be referred to from any other translation units in the entire program. All non-static functions, all extern variables (unless earlier declared static), and all file- scope non-static variables have this linkage.


到目前为止,我们在文件范围内声明的变量默认具有静态存储持续时间和外部链接。此外,在程序启动之前,具有静态存储持续时间的对象被初始化为零。
但是,看完this part (暂定定义)和 this part (声明)我找不到它说带有显式“extern”关键字的对象没有分配存储的地方。
请注意“extern”关键字本身和术语“外部声明”之间的区别。
“外部声明”定义为

At the top level of a translation unit (that is, a source file with all the #includes after the preprocessor), every C program is a sequence of declarations, which declare functions and objects with external linkage. These declarations are known as external declarations because they appear outside of any function.


无论是否存在明确的“extern”关键字。
我想我的具体问题是标准中的哪里说默认情况下具有隐式外部链接的文件范围对象如果使用显式“extern”声明,则不会分配存储空间。
我知道是这种情况,因为如果在多个翻译单元中声明相同的标识符,除了一个之外,所有翻译单元都必须具有“extern”,以免出现重新定义错误。

最佳答案

首先,虽然 cppreference.com 有有用的信息,但它不是 C 标准。可以找到 C11 标准 here .
这归结为声明和定义之间的区别。
对于一个对象,一个 声明基本上表明具有给定类型的对象存在于某处,而 定义 是实际为对象分配空间的内容。
这些术语在 C 标准的第 6.7p5 节中指定:

A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

  • for an object, causes storage to be reserved for that object;
  • for a function, includes the function body;
  • for an enumeration constant, is the (only) declaration of the identifier;
  • for a typedef name, is the first (or only) declaration of the identifier.

通过申请 extern关键字,如果没有初始值设定项,则这构成了一个声明,并且声明不会为对象分配存储空间。第 6.9.2p1-2 节详细说明了这一点:

1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

2 A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.


声明 extern并且没有初始化器不符合上述临时定义或外部定义的定义。
第 6.9.2p4 节给出了声明和定义的示例:
int i1 = 1;         //definition, external linkage
static int i2 = 2;  //definition, internal linkage
extern int i3 = 3;  //definition, external linkage
int i4;             //tentative definition, external linkage
static int i5;      //tentative definition, internal linkage

int i1;             //valid tentative definition, refers to previous
int i2;             //6.2.2 renders undefined, linkage disagreement
int i3;             //valid tentative definition, refers to previous
int i4;             //valid tentative definition, refers to previous
int i5;             //6.2.2 renders undefined, linkage disagreement

extern int i1;      //refers to previous, whose linkage is external
extern int i2;      //refers to previous, whose linkage is internal
extern int i3;      //refers to previous, whose linkage is external
extern int i4;      //refers to previous, whose linkage is external
extern int i5;      //refers to previous, whose linkage is internal

关于c - 为什么显式 "extern"不为对象分配存储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67744443/

相关文章:

c++ - 在循环运行的函数中声明变量的开销?

c - 如何释放标准图标和光标(使用 LoadIcon/Cursor(NULL, IDI/IDC_WHATEVER) 加载的图标和光标)?

c++ - 函数参数列表中的类声明

c++ - 涉及函数类型的表达式是左值还是右值?

java - java的方法声明怎么写

java - 无法引用在不同方法中定义的内部类内的非最终变量

c - 为什么应该使用二维结构数组?

c - malloc之后,如何获取更多的还是连续的内存呢?

c - 从 3 个数组中找出 3 个数字 a、b、c,其总和等于给定数字 T?

c++ - 使用透明 std 函数对象时,我们还需要写空尖括号吗?