外部有多个文件和可能的双重定义

tap*_*and 10 c extern storage-class-specifier output

我正在运行以下代码编译为: 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);
}
Run Code Online (Sandbox Code Playgroud)

方案B:

int a;
int b=2;
int fun()
{
printf("%d %d\n",a,b); 
return 0;
}
Run Code Online (Sandbox Code Playgroud)

在运行"组合"程序时,输出为:

1 2
1 2
Run Code Online (Sandbox Code Playgroud)

现在,我对这个问题有些疑惑:

  1. 为什么不输出:

    0 2

    1 0

  2. 是不是a和b定义了两次?

请清楚地解释一下,我在了解外部时遇到了很多问题,而且很少有这些疑虑不时出现.

提前致谢.

Day*_*rai 5

只要声明彼此一致并与定义一致,就可以多次声明变量.它可以在许多模块中声明,包括定义它的模块,甚至在同一模块中多次.

外部变量也可以在函数内声明.在这种情况下,必须使用extern关键字,否则编译器会将其视为局部变量的定义,该变量具有不同的范围,生命周期和初始值.此声明仅在函数内部可见,而不是在整个函数模块中可见.

现在让我再次重复一下extern的定义,其中"外部变量是在任何功能块之外定义的变量"(请仔细阅读BOLD中给出的单词).因此,对于Programe A a有定义,但b仅仅是声明,以便将的extern寻找它这是在给定的"B"的定义Programe B.所以从打印Programe A1 2.现在让我们来谈谈Programe B它具有声明a和定义b因此被priting的价值aprograme A和值的b从当前文件.


tap*_*and 4

所以,我在很长一段时间后回答我自己的问题。虽然声明:

int b;是声明,int b = 2;是定义

是正确的,但每个人给出的原因尚不清楚。

如果没有int b = 2;,int b;是定义,那么有什么区别呢?

区别在于链接器处理多个符号定义的方式。有一个弱符号和强符号的概念。

汇编器将此信息隐式编码在可重定位目标文件的符号表中。函数和初始化的全局变量获得强符号。未初始化的全局变量会得到弱符号。

所以在 中Program Aint a = 1是强符号int b;,而 是弱符号,同样在 中Program Bint b = 2是强符号,而int a是弱符号。

鉴于强符号和弱符号的概念,Unix 链接器使用以下规则来处理多重定义的符号:

  1. 不允许使用多个强符号。
  2. 给定一个强符号和多个弱符号,选择强符号。
  3. 给定多个弱符号,选择任何一个弱符号。

所以,现在我们可以争论上述案例中发生的事情了。

  1. 其中int b = 2int b,前者是强符号,后者是弱符号,所以b定义为值2。
  2. int a = 1和中int a,a 定义为1(同理)。

因此,输出1 2.