为什么在C中我可以定义一个变量两次?

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

我一直在测试全局变量、定义和声明,然后我就停在了这种情况下:

main.c:

#include "stdio.h"

void func(void);
int a;

int main(void) {
    a = 20;
    printf("in main: %d\n", a);
    func();
    
    return 0;
}

添加.c:

#include <stdio.h>

void func(void);
int a;

void func() {
    printf("in add: %d\n", a);
}

所以在 C 中

int a;

既表示声明又表示定义,但我们知道不允许多次定义一个变量。那么,如果我们有两个

a
的定义和声明,为什么这段代码能够编译呢? 我正在 CLion 中工作,当我在 main 中的
a
上按“转到定义/声明”时,它将指针移动到 add.c 中的
a
,当我在 add.c 中执行相同操作时,它会向后移动到 main.c,所以我无法理解这里发生了什么。

c global-variables declaration definition
1个回答
9
投票

在任何函数之外,

int x;
是一个暂定定义,一些编译器和链接器将它们视为一种“协作定义”,其中可以在多个文件中以这种方式声明标识符,并且将导致仅定义一个对象。

由于历史原因,C 的外部声明(函数之外的声明)规则有点复杂 - C 是随着不同的人开发和实验而成长的,而不是根据我们今天所拥有的知识进行设计的。

定义:

int x = 3;
是一个定义。它既声明了标识符
x
,又为
int
保留了内存,并将
int
初始化为 3。

声明:

extern int x;
是声明,而不是定义。它声明了标识符
x
但不为其保留内存。

extern int x;
提供
x
外部链接,如果
int x = 3;
出现在函数外部,则它也是如此。外部链接意味着,当它们出现在不同的源文件中时,标识符的两个实例将被链接以引用内存中的同一事物。

C 标准规定,具有外部链接的标识符“应该”最多有一个定义 (C 2018 6.9 5)。 (如果程序中使用了标识符,则必须有定义。如果表达式中没有使用标识符,则不需要定义。)

暂定定义:

int x;
是一个混合体。在函数之外,它是一种特殊的声明,称为“暂定定义”。 C 标准规定,如果翻译单元(正在编译的源文件及其包含的所有文件)中有暂定定义,并且没有常规定义,则会创建常规定义。 现在,如果你违反了“最多应该有”一个定义的规则,会发生什么?事情是这样的:这不是程序必须遵守的规则。当 C 标准说“应该”时,意味着如果程序遵守此规则,则行为将如 C 标准所述。如果程序违反此规则,C 标准不会定义该行为 (C 2018 4 2)。相反,我们让编译器和链接器定义行为,如果他们的设计者选择这样做的话。

当程序违反最多一个定义的规则时,编译器和链接器中的一种常见行为(但不是唯一的可能性)是:

链接时如果有多个正则定义,报错。
  • 如果有多个定义来自暂定定义,但来自常规定义的定义不超过一个,请将它们合并为一个定义。
  • 这是 GCC 版本 10 之前的 GCC 和相关工具中定义的默认行为,并在 C 2018 标准 J.5.11 中有关常见扩展的信息部分中明确提到。在当前版本的 GCC 中,任何类型的多个定义默认都会被视为错误。您可以使用命令行开关请求旧行为
-fcommon

    

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