c中extern的奇怪行为

时间:2013-09-15 06:54:27

标签: c

我对extern的以下行为感到惊讶。

当我运行时

#include<stdio.h>
int main()
{
    extern int a;
    printf("%d\n", a);
    return 0;
}
int a=20;

输出: 20(在gcc Linux 32位,看起来没问题)

但是当我在a

中声明变量main()
#include<stdio.h>
int main()
{
    extern int a;
    int a=20;
    printf("%d\n", a);
    return 0;
}

输出:

extern.c: In function ‘main’:
extern.c:5:9: error: declaration of ‘a’ with no linkage follows extern declaration
extern.c:4:16: note: previous declaration of ‘a’ was here

为什么我在将a的范围从全局更改为本地后立即收到错误?为什么它现在不允许重新声明a,而在之前的情况下允许重新声明。

2 个答案:

答案 0 :(得分:7)

extern声明的要点是告诉编译器有关多个编译单元(.c文件)使用的全局变量或函数,但是在单个编译单元中定义和分配。 extern声明放在所有单元包含的头文件中,单个编译单元包含实际定义,因此同时看到两者。

您的第一个示例是合法C:您声明 a将引用外部定义的变量,然后继续定义该变量当前的编译单位。通常情况下,extern声明将包含在头文件中,因此在顶层显示给编译器,而不是在函数内部,但编译器无关紧要。换句话说,这里没有重新定义,只有声明后的定义。

您的第二个示例声明a具有外部链接,然后继续将其定义为main中的局部变量。声明和定义显然是不兼容的 - 如果a是一个局部变量,它不能只在一个地方定义和分配 - 它会在每次调用函数时自动分配到堆栈上。这种不兼容性导致错误诊断。

答案 1 :(得分:4)

在第一个例子中,你告诉编译器:“嘿,我有一个名为a的变量,它在其他地方定义。”然后你使用它。没关系。

#include<stdio.h>
int main()
{
    extern int a;
    printf("%d\n", a);
    return 0;
}
int a=20;

在第二个示例中,您还告诉编译器程序中某处有一个名为a的变量,然后在堆栈中声明一个具有相同名称的新变量。这没有多大意义,编译器说了两件事:在程序中找不到任何变量a的声明,变量a已经存在(如果你修复了第一个错误,它会)。

#include<stdio.h>
int main()
{
    extern int a;
    int a=20;
    printf("%d\n", a);
    return 0;
}

声明全局变量时,会在程序启动时分配其内存(它位于二进制文件中并映射到内存中)。声明局部变量时,在执行函数期间会在堆栈上分配内存。您不能将extern引用到尚不存在的变量。