C 中全局变量的行为

Behaviour of global variable in C

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

#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,那为什么第一种情况会产生警告呢?

第一种情况需要在运行时为一个未指定长度的数组分配内存。这就是 "hard",这就是为什么编译器通过假设长度为 1 来抱怨和作弊的原因。

第二种情况只需要别人提供一个数组的基地址,而确保在提供的位置分配内存是别人的问题。

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

C11 草案甚至有一个明确的例子:

extern int *x;
extern int y[];

The first declares x to be a pointer to int; the second declares y to be an array of int of unspecified size (an incomplete type), the storage for which is defined elsewhere.

当你写一个

char arr[];

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

写的时候

extern char arr[];

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

注意你的用语有点混乱:

By default global variables are extern

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

外部链接意味着变量可以从不同的翻译单元(另一个源文件)引用,如果它被声明为 extern 的话。 extern 说明符声明变量应在别处使用外部链接定义。

这就解释了你的问题:

char arr[];

是一个带有外部链接的字符数组的暂定(此处不正确)定义。由于未指定大小并且无法从初始值设定项中推导出来,因此无法完全定义数组。由于它没有被声明为 extern 并且在该翻译单元中不存在完整的定义,因此它是一个错误的定义。

extern char arr[];

另一方面,只有声明 arr 是一个字符数组,假设它在别处定义,可能在不同的翻译单元中。如果没有定义,程序将是错误的,不需要诊断。

但这是一个完全正确的程序:

#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

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