在全局范围内两次声明相同的静态变量
Posted
技术标签:
【中文标题】在全局范围内两次声明相同的静态变量【英文标题】:Declaring Same Static Variable Twice in Global Scope 【发布时间】:2021-12-24 06:33:03 【问题描述】:我发现了这个问题,C 中的同一个静态变量在同一范围内被声明了两次,但代码中没有编译错误。这是怎么回事?
#include<stdio.h>
static int i = 90;
int main()
printf("%d", i);
return 0;
static int i;
【问题讨论】:
为了好玩,尝试在第二行添加一个初始化器...... 第一个是定义。第二个是暂定定义。 Here's a similar question 有更多关于暂定定义的信息。长话短说,存在与旧(1989 年之前)编译器向后兼容的暂定定义,不应在新代码中使用。 这能回答你的问题吗? What is the rationale behind tentative definitions in C? 仅供参考,请注意标题中的“全局范围”,C 没有全局范围(在整个程序中可见)。这些声明是 external(在任何函数之外),带有 internal links 和 file scope(在翻译单元的其余部分可见)。具有外部链接的标识符可以在多个翻译单元中使用,但这与全局范围不同,因为它需要在每个单元中声明并且通过链接而不是范围来实现。 除非询问语言之间的差异或交互,否则不要同时标记 C 和 C++。选择一个标签并删除另一个。 【参考方案1】:声明不一定定义对象(为它们保留内存)。从根本上说,声明描述了一个标识符。例如:
extern int x;
描述了一个名为 x
的对象,但不为其保留内存。
typedef char foo;
描述了一个名为 foo
的类型。
struct foo int x;
描述了一个结构化的标签 foo
。
一些声明也定义了对象。对于外部声明(这里,“外部”表示它出现在任何函数之外),C 2018 6.9.2 1 说:
如果对象标识符的声明具有文件范围和初始化程序,则该声明是标识符的外部定义。
所以static int i = 90;
在文件范围内既声明又定义i
。
但是,static int i;
没有定义 i
,因为它没有初始化程序。
C 2018 6.9.2 2 说:
具有文件范围的对象的标识符声明没有初始化程序,没有存储类说明符或具有存储类说明符
static
,构成暂定定义...
这表示static int i;
是一个暂定定义。尽管该名称中出现了“定义”一词,但它不是一个定义(就像潜在员工还不是员工并且可能永远不会成为员工)。
C 2018 6.9.2 2 继续说:
... 如果一个翻译单元包含一个或多个标识符的暂定定义,并且该翻译单元不包含该标识符的外部定义,那么该行为就像翻译单元包含该标识符的文件范围声明一样,具有翻译单元末尾的复合类型,初始化器等于 0。
因此,如果翻译单元不包含定义static int i = 90;
,则暂定定义static int i;
将导致创建定义。但是,事实并非如此,因此这句话不适用。 static int i;
仍然是一个暂定定义,只是一个声明。这不是i
的第二个定义,因此不违反具有内部链接的标识符的外部定义不得超过一个的规则(C 2018 6.9 3)。
这些关于暂定定义的规则是围绕具有公共变量的历史实践而发展起来的,在 FORTRAN 中,这些公共变量将在多个翻译单元中声明,并且链接器会将所有同名声明解析为可执行程序中的单个对象。如果我们今天从头开始重新设计 C,我们可能会为声明和定义创建更清晰的语法。
【讨论】:
以上是关于在全局范围内两次声明相同的静态变量的主要内容,如果未能解决你的问题,请参考以下文章