如果我将数组声明为像这样的全局:
#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
,那么为什么第一个案例会产生警告?
答案 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
暂定定义仅被视为前瞻性声明。由于定义存在于翻译单元中,编译器很高兴...