我试图了解如何将两个文件与一个变量连接起来。我知道标准的方法是通过extern关键字,如下所示。
档案1
#include<stdio.h>
int i;
void func1();
int main()
{
i = 10;
func1();
printf("i value with method 1: %d\n", i);
}
档案2
extern int i;
void func1()
{
i = i+1;
}
编译和执行=> gcc *.c ./a.out
方法1: 11的Output=> i值
我发现的一件事是通过标题,如下所示:
common.h
#ifndef __COMMON_H
#define __COMMON_H
int i;
#endif
档案1
#include<stdio.h>
#include"common.h"
int main()
{
i = 10;
func1();
printf("i value with method 2: %d\n", i);
}
档案2
#include"common.h"
void func1()
{
i = i+1;
}
编译和执行=> gcc *.c ./a.out
方法2: 11的Output=> i值
我怀疑的是,method2是如何工作的?
发布于 2022-03-24 11:47:55
在文件范围内,int i;
是一种特殊的声明,称为暂定定义。尽管它的名称,但它不是一个定义。但是,它可以导致创建一个定义。
声明和定义在多个翻译单元中使用的对象的一种干净方法是在每个使用对象的单元中包含的标题中声明该对象:
extern int i;
并在一个翻译单元中定义对象:
int i = 0;
在文件范围内,int i = 0;
是一个定义;使用= 0
进行初始化使其成为一个常规定义,而不是一个暂定定义。
理想情况下,所有源代码都使用干净的声明和定义。然而,C并不是事先完全计划和设计的。它是通过实验发展起来的,不同地方的不同人实现了不同的东西。当C委员会标准化C时,他们必须处理不同的实践和实现。一种常见的做法是在多个单元中使用诸如int i;
这样的声明来创建单个i
。(这种行为是从FORTRAN继承的,FORTRAN具有类似的公共对象。)
为了适应这一点,委员会将文件范围内的int i;
描述为一种特殊的声明,一个暂定定义。如果在定义相同标识符的同一个翻译单元中有一个常规定义,则暂定定义充当一个简单的声明,而不是定义。如果没有常规定义,编译器(或C实现的其他部分)会为标识符创建一个定义,就好像它是用零初始化的一样。
C标准将多个暂定定义与每个C实现保持一致;它不定义在多个翻译单元中使用int i;
时的行为。在第10版之前,GCC的默认行为是使用“公共符号”行为;链接时,多个暂定定义将与单个定义相一致。(为了支持这一点,编译器在创建对象模块时标记暂定定义与常规定义不同,因此链接器知道哪个是哪个。)在第10版中,默认情况发生了变化,GCC现在将暂定定义所产生的定义视为常规符号,而不是普通符号。
这就是为什么您将看到一些人报告当您和其他人不使用暂定定义链接源时会出现错误。这只是他们使用哪个版本的编译器和链接器的问题。
您可以显式地使用GCC开关-fcommon
请求常见符号行为,也可以为常规符号行为显式请求-fno-common
。
通常,您应该使用上面的clean方法;在标头中声明带有extern
的标识符,并在一个源文件中在每个标识符中准确地放置一个定义。
https://stackoverflow.com/questions/71599192
复制相似问题