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

时间:2013-07-01 04:58:05

标签: c output extern storage-class-specifier

我正在运行以下代码: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

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

  1. 为什么输出不是:

    0 2

    1 0

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

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

    先谢谢。

4 个答案:

答案 0 :(得分:5)

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

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

现在让我再次重复一下extern的定义,其中“外部变量是一个变量 DEFINED 在任何功能块之外”(请仔细阅读 BOLD 中给出的单词)。 因此,对于Programe A a有定义,但b只是声明,因此extern会查找{b}中对Programe B的定义。所以打印来自{{ 1}}是Programe A。现在让我们谈谈1 2声明Programe Ba的定义,以便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 Bint b = 2是一个强大的符号,而int a很弱。

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

  1. 不允许使用多个强符号。
  2. 如果选择强符号和多个弱符号,请选择强符号。
  3. 给定多个弱符号,选择任何弱符号。
  4. 所以,现在我们可以争论上述案例中发生了什么。

    1. int b = 2int b中,前者是强符号,而后者是弱符号,因此b定义为值2.
    2. int a = 1int a中,a被定义为1(相同的推理)。
    3. 因此,输出 1 2

答案 2 :(得分:2)

因为变量在这里没有定义两次;他们被宣布两次。这些函数采用变量定义中的值而不是变量声明。

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

extern int a;

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

请阅读on this link 以获取进一步参考。

there is this wonderful 也发布了stackoverflow。

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

程序A中的

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都被定义为两个文件中的全局变量。 如果两者都在函数内定义,则情况可能不同。 欢迎提出任何建议或其他意见。