10

我正在运行以下一起编译的代码:gcc A.c B.c -o combined

方案一:

#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

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

  1. 为什么没有输出:

    0 2

    1 0

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

请清楚地解释这些,我在理解 extern 时遇到了很多问题,而且这些疑问很少不时出现。

提前致谢。

4

4 回答 4

5

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

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

现在让我再次重复 extern 的定义,它说“外部变量是在任何功能块之外定义的变量”(请仔细阅读BOLD中给出的单词)。因此,对于Programe A ahave 定义但b只是声明,因此 extern 将查找其在Programe B.so print from Programe Ais中给出的 'b' 的定义。1 2现在让我们谈谈Programe B哪些有声明a和定义,b因此它是afromprograme A和 value 的 priting value来自b当前文件。

于 2013-07-01T05:53:03.707 回答
4

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

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

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

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

不同之处在于链接器处理多个符号定义的方式。有弱符号和强符号的概念。

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

所以 in Program A,int a = 1是强符号,而int b;是弱符号,类似地, in Program B,int b = 2是强符号,而 whileint a是弱符号。

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

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

因此,现在我们可以讨论上述案例中发生的情况。

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

因此,输出1 2

于 2016-06-29T04:43:00.920 回答
2

因为变量在这里没有定义两次;虽然它们被声明了两次。这些函数从变量定义中获取值,而不是从变量声明中获取值。

声明引入了一个标识符并描述了它的类型。通过声明,我们向编译器保证该变量或函数已在程序的其他地方定义,并将在链接时提供。例如声明是:

extern int a;

定义实际上实例化/实现了这个标识符。定义是: int a=5;int a;

只需阅读此链接以供进一步参考。

stackoverflow 上也有这篇精彩的帖子。

extern告诉编译器变量是在外部定义的,因此它会在函数外部查找并在那里找到:

int a=1在程序 A 和int b=2程序 B 中

对于自动变量:

int a;//both definition and declaration

有关存储类的更多知识,您可以点击此链接

int a在 main 或任何其他函数之外是声明(即 GLOBAL),仅在其调用定义的任何函数内部。

于 2013-07-01T05:52:25.070 回答
1

据我所知:输出将是 1 2 和 1 2,因为您将 a 和 b 定义为 main 函数中的外部变量。因此它也会尝试从其他文件中获取值。至于第二个问题,我认为编译器正在获取变量的初始化值并将它们合并,因为 a 和 b 在两个文件中都被定义为全局变量。如果两者都在函数内部定义,则大小写可能不同。欢迎任何建议或其他意见。

于 2013-07-01T05:46:05.527 回答