Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 多个文件中的Extern和可能的双重定义_C_Output_Extern_Storage Class Specifier - Fatal编程技术网

C 多个文件中的Extern和可能的双重定义

C 多个文件中的Extern和可能的双重定义,c,output,extern,storage-class-specifier,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); } 运行“组合”程序时,输出为: 1 2 1 2 现在,我对这个有一些疑问: 为什么输出不是: 02 10 a和b不是定义了两次吗 请把这些解释清楚,我在理解extern时遇到了很多问题,很少有人会时不时

我正在运行以下代码,这些代码被编译为:
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);
}
运行“组合”程序时,输出为:

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

  • 为什么输出不是:

    02

    10

  • a和b不是定义了两次吗

  • 请把这些解释清楚,我在理解extern时遇到了很多问题,很少有人会时不时地怀疑

    提前谢谢。

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

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

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

    extern-int-a

    定义实际上实例化/实现了该标识符。 定义是:
    inta=5
    inta

    请阅读以供进一步参考

    也在stackoverflow上发布

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

    程序a中的
    int a=1
    和程序b中的
    int b=2

    对于自动变量:

    inta//定义和声明

    有关存储类的更多信息,您可以


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

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

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

    现在,让我再次重复extern的定义,即“外部变量是在任何功能块之外定义的变量”(请仔细阅读粗体)。
    因此,对于
    程序A
    A
    有定义,但
    b
    只是声明,因此extern将查找
    程序b
    中给出的“b”的定义。因此,从
    程序A
    打印是
    12
    。现在让我们谈谈
    程序b
    ,它有
    A
    的声明,并且
    b
    的定义,因此它是
    程序a
    a
    的priting值和当前文件中
    b
    的priting值。

    因此,我在很长时间后回答了自己的问题。尽管声明:

    intb是一个十分音符,且
    intb=2是定义

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

    如果没有a
    intb=2
    intb是一个定义,那么区别是什么

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

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

    因此,在
    程序A
    中,
    int A=1
    是一个强符号,而
    int b是弱符号,类似地,在
    程序B
    中,
    int B=2
    是强符号,而
    int a
    是弱符号

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

  • 不允许使用多个强符号
  • 给定一个强符号和多个弱符号,选择强符号
  • 给定多个弱符号,请选择任意弱符号
  • 所以,现在我们可以讨论在上述情况下发生了什么

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

  • 因此,输出
    12

    你试图欺骗编译器,而编译器欺骗了你。这不是欺骗编译器,而是让概念正确;是声明和定义,并且在任何函数之外生效。它也成为值为0的初始化。考虑一下:int main(){int a;//声明和定义都有……int a=5;//给出了a的多个错误定义。}你也可以对外部变量尝试同样的方法;这两种方法都声明并定义了内存分配。在任何函数之外,它还使用定义良好的值(0)而不是垃圾值初始化它。很抱歉,最近出现了电源问题。。。。您所说的可能适用于自动变量,但不适用于外部变量,请查看链接i
    1 2
    1 2