C中的外部行为
如果我声明int Array[10];
在file1.c中
在file2.c中,如果II具有这样的function
extern int *Array; fun() { Array[0]=10; }
这有没有问题?
是的,有问题。
您声明一个Array
是一个指针 ,而它是一个数组 。 这两个是非常不同的对象,在这里你基本上是向编译器提供虚假信息。
请注意,在两种情况下访问元素的C语法都是Array[0]
,但如果Array
是指针变量,则所需的机器代码将不同于Array
是否是数组(指针有一个额外的间接)。
例如,如果Array1
声明为extern int *Array
,则由Array1[ix] += 3
生成的机器代码由gcc生成:
movslq ix(%rip), %rax ;; Load index value from location ix movq Array1(%rip), %rdx ;; Load pointer value from location Array1 leaq (%rdx,%rax,4), %rax ;; Compute rax as pointer + index*4 addl $3, (%rax) ;; Add 3 to the location pointed by rax
如果将Array2
声明为extern int Array2[10]
,则Array2[ix] += 3
的代码就是:
movslq ix(%rip), %rax ;; Load in rax the index value from location ix addl $3, Array2(,%rax,4) ;; Add 3 to the location Array2 + index*4
正如您在第一种情况中所看到的那样,存在一个额外的间接,并且读取地址Array1
处的内存内容以查找应在内存中进行增量的位置。 在第二种情况下,只需要读取索引来计算要递增的位置。
为了使C中的事情更加混乱,在很多情况下,数组“衰减”成指向第一个元素的指针,例如,如果你有一个函数,期望一个指针传递一个数组就好了,因为编译器将负责处理差异。
必须告诉编译器内存中的对象是数组还是指针,因为语义不同; 问题中的代码恰恰是这样……程序的一部分分配一个数组并告诉程序的某些部分它是一个指针。
声明extern int *Array
不声明数组,因此与实际定义不匹配。 你必须声明:
extern int Array[];
C99(ISO / IEC 9899)§6.5.7.2 数组声明符
注意声明之间的区别
extern int *x; extern int y[];
第一个声明x是一个指向int的指针; 第二个声明y是一个未指定大小的int数组(一个不完整的类型),其存储在其他地方定义。