我正在运行以下代码:gcc A.c B.c -o combined
计划A:
#include<stdio.h>
int a=1;
int b;
int main()
{
extern int a,b;
fun();
printf("%d %d\n",a,b);
}
计划B:
int a;
int b=2;
int fun()
{
printf("%d %d\n",a,b);
return 0;
}
在运行“组合”程序时,输出为:
1 2
1 2
现在,我对这个问题有些怀疑:
为什么输出不是:
0 2
1 0
是不是a和b定义了两次?
请清楚解释一下,我在了解外部时遇到了很多问题,而且很少有这些疑虑不时出现。
先谢谢。
答案 0 :(得分:5)
只要声明彼此一致并与定义一致,就可以多次声明变量。它可以在许多模块中声明,包括定义它的模块,甚至在同一模块中多次。
外部变量也可以在函数内声明。在这种情况下,必须使用extern关键字,否则编译器会将其视为局部变量的定义,该变量具有不同的范围,生命周期和初始值。此声明仅在函数内部可见,而不是在整个函数模块中可见。
现在让我再次重复一下extern的定义,其中“外部变量是一个变量 DEFINED 在任何功能块之外”(请仔细阅读 BOLD 中给出的单词)。
因此,对于Programe A
a
有定义,但b
只是声明,因此extern会查找{b}中对Programe B
的定义。所以打印来自{{ 1}}是Programe A
。现在让我们谈谈1 2
声明Programe B
和a
的定义,以便b
从{a
开始值programe A
1}}和来自当前文件的b
的值。
答案 1 :(得分:3)
所以,经过很长一段时间,我正在回答我自己的问题。声明虽然声明:
int b;
是一个decalaration,int b = 2;
是定义
是正确的,但每个人给出的理由都不清楚。
如果没有int b = 2;
,int b;
是一个定义,那有什么区别?
不同之处在于链接器处理多个符号定义的方式。 有一个弱而强的符号概念。
汇编程序隐式地在可重定位目标文件的符号表中对此信息进行编码。函数和初始化的全局变量获得强符号。未初始化的全局变量得到弱符号。
因此,在Program A
中,int a = 1
是一个强符号,而int b;
是一个弱符号,类似于Program B
,int b = 2
是一个强大的符号,而int a
很弱。
鉴于强弱符号的这一概念,Unix链接器使用以下规则来处理多重定义的符号:
所以,现在我们可以争论上述案例中发生了什么。
int b = 2
和int b
中,前者是强符号,而后者是弱符号,因此b定义为值2. int a = 1
和int a
中,a被定义为1(相同的推理)。因此,输出 1 2
。
答案 2 :(得分:2)
因为变量在这里没有定义两次;他们被宣布两次。这些函数采用变量定义中的值而不是变量声明。
声明引入了一个标识符并描述了它的类型。通过声明,我们向编译器保证,该变量或函数已在程序中的其他位置定义,并将在链接时提供。 例如,声明是:
extern int a;
定义实际上实例化/实现此标识符。
定义是:
int a=5;
或int a;
请阅读on this link 以获取进一步参考。
there is this wonderful 也发布了stackoverflow。
extern
告诉编译器变量是在外部定义的,因此它看起来在函数外部并且在那里找到:
int a=1
和程序B中的int b=2
对于AUTO变量:
int a;//both definition and declaration
有关存储类别的进一步了解,您可以follow this link
主要或任何其他函数之外的 int a
仅在其调用的任何函数内声明(即GLOBAL)。
答案 3 :(得分:1)
据我所知: 输出将是1 2和1 2,因为您在主函数中将a和b定义为外部变量。因此它也会尝试从其他文件中获取值。 至于第二个问题,我认为编译器正在采用变量的初始值并合并它们,因为a和b都被定义为两个文件中的全局变量。 如果两者都在函数内定义,则情况可能不同。 欢迎提出任何建议或其他意见。