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
暂定定义仅被视为前瞻性声明。由于定义存在于翻译单元中,编译器对此很满意...
如果我像这样将数组声明为全局数组:
#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 toint
; the second declaresy
to be an array ofint
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
暂定定义仅被视为前瞻性声明。由于定义存在于翻译单元中,编译器对此很满意...