Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么我可以在C中定义一个变量两次?_C_Global Variables_Declaration_Definition - Fatal编程技术网

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

为什么我可以在C中定义一个变量两次?,c,global-variables,declaration,definition,C,Global Variables,Declaration,Definition,我一直在测试全局变量、定义和声明,我在这种情况下停了下来: 主要条款c: #include "stdio.h" void func(void); int a; int main(void) { a = 20; printf("in main: %d\n", a); func(); return 0; } add.c: #include <stdio.h> void func(void); int

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

主要条款c:

#include "stdio.h"

void func(void);
int a;

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

#include <stdio.h>

void func(void);
int a;

void func() {
    printf("in add: %d\n", a);
}
表示声明和定义,但我们知道不允许多次定义变量。那么,如果我们对
a
有两个定义和两个声明,那么为什么要编译这段代码呢?
我在CLion中工作,当我在main中按下
a
上的“Go to Definition/Declaration”时,它会将指针移到add.c中的
a
,当我在add.c中执行相同操作时,它会移回main.c,因此我无法理解这里发生了什么是一个暂定的定义,一些编译器和链接器将其视为一种“协作定义”,在这种定义中,标识符可以在多个文件中以这种方式声明,并且只定义一个对象

由于历史的原因,C的外部声明规则(函数之外的声明)有点复杂——C是随着不同的人开发和试验而发展起来的,而不是通过我们今天所拥有的知识进行设计

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

声明:
外部INTX是声明,但不是定义。它声明标识符
x
,但不为其保留内存

这两个声明都提供了
x
外部链接。这意味着,当它们出现在不同的源文件中时,标识符的两个实例将被链接以引用内存中的相同内容

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

暂定定义:
intx是一种混合。这是一种特殊的可能定义,称为试探性定义。C标准规定,如果翻译单元中有一个暂定定义(正在编译的源文件及其包含的所有文件),而没有常规定义,则暂定定义将成为常规定义

现在,如果你违反了“应该有”最多一个定义的规则,会发生什么?事情是这样的:这不是一个程序必须遵守的规则。当C标准说“应该”时,它意味着,如果一个程序遵守这条规则,其行为将如C标准所说。如果程序违反此规则,C标准不会定义该行为(C 2018 4 2)。相反,我们让编译器和链接器定义行为

当程序违反关于最多一个定义的规则时,编译器和链接器中的常见行为是:

  • 如果链接时有多个常规定义,请报告错误
  • 如果有多个暂定定义,但只有零个或一个常规定义,请将它们合并为一个定义

这是GCC和GCC版本10之前的相关工具中定义的默认行为,并在C 2018标准关于通用扩展的信息部分中明确提到,见J.5.11。在当前版本的GCC中,默认情况下,任何类型的多个定义都被视为错误。您可以使用命令行开关
-fcomon

请求旧的行为,这里您可能需要一个
add.h
文件,该文件具有
void func(void)
外部内部a。然后在
main.c
中加入“add.h”
。然而,全局变量是令人讨厌的它是一个“通用”符号。参见我的答案:有关解释,请使用调用为
gcc-Wall-Wextra-g-c
的编译器编译
main.c
add.c
,然后链接到
gcc main.o add.o-o yourprog
然后使用
yourprog
可执行文件上的调试器。务必阅读编译器和调试程序的文档。由于存在标识符
a
的两个外部定义,程序的行为未定义,这并不意味着您可以依靠编译器拒绝程序,甚至诊断问题。“未定义”指“未定义”。值得一提的是许多编译器使用的附录J.5.11(通用扩展-多个外部定义)implement@M.M:谢谢,完成了。
int a;