我的程序中有两个源文件。
数组在 A.cpp 。
中定义// compiler: MSVC2005 SP2
// A.cpp
// defines an array of type "int [100]"
int a[100] = {3};
用于 B.cpp 。
// B.cpp
// declares an array of type "int []"
extern int a[];
int main()
{
// prints 3 correctly
cout << a[0] << endl;
return 0;
}
AFAIK,如果使用声明的标识符,如果找不到声明的任何匹配定义,链接器将引发错误。在这里, int [] 和 int [100] 显然是两种不同的类型。
在这种情况下,为什么没有链接错误? 标准是否保证在声明/定义匹配期间数组大小是微不足道的?或者它只是特定于实现?如果有的话,标准的引用将会受到赞赏。
编辑: iammilind在他的回答中提到链接器可以正确运行(他的编译器是gcc)即使类型在声明和定义之间不匹配。是标准要求还是gcc的方式?我想这是一个非常重要的问题。
答案 0 :(得分:7)
在C和C ++中,不完整类型的对象a
的声明将匹配类型完整的对象a
的定义。您观察到的只是说明了在C ++中允许在非定义声明中使用不完整类型的事实。但是一旦达到定义,类型必须完整。
此行为不限于数组。例如,您可以声明
extern class X x;
对于一个完全未知的类X
,然后,当class X
已经完全定义时,您可以定义
X x;
将与上述声明相匹配。
您的阵列也会发生同样的事情。首先声明一个不完整类型的对象
extern int a[];
然后用完整类型
定义它int a[100];
这里的类型确实不匹配。但是,C ++语言从未要求它们匹配。例如,3.9 / 7明确说明
数组对象的声明类型可能是未知大小的数组 因此,在翻译单位的某一点上不完整 稍后完成;这两个点的数组类型(“数组的数组 未知的T“和”N T“数组的界限是不同的类型。
这意味着相同的数组对象最初可能具有不完整的类型,但稍后会获得完整的类型。 (另见3.9 / 7中的例子)。当然,这并不意味着您可以将a
声明为int
,然后将其定义为double
。你在这里唯一与类型相关的自由是完成一个不完整的类型。没有了。
答案 1 :(得分:1)
首先,代码不应该给出任何错误。规范int a[]
与a[100]
不同,但与之兼容(它只是不完整)。
第二个重点是,您不能指望C ++编译器/链接器为跨模块不连贯性提供错误。例如,在C ++程序中,您不能使用不同的定义将同一个类定义两次,但编译器不需要告诉您这个问题,这对程序员来说是一个负担。
如果某个实现检测到并发出此类问题的信号,那么很好,但是实现没有告诉他们任何事情,只是创建崩溃的可执行文件仍然完全符合。
答案 2 :(得分:0)
这里说“C ++允许将方括号留空[]。在这种情况下,编译器将假定数组的大小与大括号{}之间包含的值的数量相匹配”。因此,如果这个参考文献是正确的,它似乎是标准的一部分。
答案 3 :(得分:0)
你的问题是真的。这里几乎没有问题。
当您声明两个具有相同名称的符号时;然后没有检查
来自链接器的类型/大小等。它只是解决它们和
将它们联系在一起。例如,尝试声明extern float
a[];
或extern int a[3];
它仍然有效。这就是C ++的方式
(不幸的是)设计了链接器。
所以解决方案是在头文件中声明它们,并在a.cpp和b.cpp中声明#include
。
答案 4 :(得分:0)