C中全局变量的行为

时间:2018-01-31 10:30:41

标签: c arrays global-variables extern

如果我将数组声明为像这样的全局:

#include <stdio.h>

char arr[];

int main()
{
    return 0;
}

编译器生成警告:

test.c:3:6: warning: array ‘arr’ assumed to have one element [enabled by default]
 char arr[];

但是,如果我将数组声明为全局且显式提供extern关键字,如下所示:

extern char arr[];

int main()
{
    return 0;
}

然后,它在没有警告的情况下编译好。

但是,默认全局变量是extern,那么为什么第一个案例会产生警告?

3 个答案:

答案 0 :(得分:8)

第一种情况需要在运行时为未指定长度的数组分配内存。这很“难”,这就是编译器通过假设长度为1来抱怨和欺骗的原因。

第二种情况只需要其他人为数组提供基地址,并且确保在提供的位置分配内存是有问题的。

不完全确定细节如何着陆,但这是两者之间的基本区别。

C11草案甚至以此为例:

  

extern int *x;
  extern int y[];

     

第一个声明x是指向int的指针;第二个声明y是一个未指定大小的int数组(一个不完整的类型),其存储在其他地方定义。

答案 1 :(得分:5)

当你写

char arr[];

在全球范围内,您的目的是定义具有静态生命周期的数组。因此,您必须指定它包含的元素数量。

写作时

extern char arr[];

它只是一个声明,告诉编译器一个名为arr的数组存在于其他地方,这里没有定义。因此不需要大小。

答案 2 :(得分:4)

请注意您的条款有点混乱:

  

默认情况下,全局变量是extern

不完全是:全局变量具有外部链接,除非它们被声明为静态。在后一种情况下,他们有内部联系

外部链接意味着如果变量在那里被声明为extern,则可以从不同的翻译单元(另一个源文件)引用该变量。 extern说明符声明应该使用外部链接在其他地方定义变量。

这解释了你的问题:

char arr[];

是具有外部链接的字符数组的暂定(此处不正确)定义。由于未指定大小且无法从初始化程序推断,因此无法完全定义数组。因为它没有被声明为extern,并且因为该翻译单元中不存在完整的定义,所以它是一个不正确的定义。

extern char arr[];

另一方面,只有声明 arr是一个char数组,假设在其他地方定义,可能在不同的翻译单元中。如果没有定义,该程序将形成错误,无需诊断。

但这是一个非常正确的计划:

#include <stdio.h>

char arr[];  // tentative definition

int main()
{
    // can use arr here, except for sizeof(arr) which would be an error
    // because only a declaration (not a definition) has been seen to this point
    return 0;
}

char arr[] = "abcd";  // full definition: the size is deduced to be 5

暂定定义仅被视为前瞻性声明。由于定义存在于翻译单元中,编译器很高兴...