我找不到标准中的相关位,但是gcc和clang允许它,所以我想我想知道它是编译器扩展还是语言的一部分。如果可以,请提供链接。
这可以通过以下方式产生:
extern char arr[];
func(arr[7]); /*No error.*/
LATE EDIT:我认为我最好清楚地理解这一点,虽然我已经离开了,但我从未做过这样的事情,所以我将奖励给第一个给我一个明确,简洁的参考资料( es)在C89标准中为什么允许这样做。如果没有人能在C89中找到答案,C99是可以接受的,但你需要先查看C89标准。
答案 0 :(得分:4)
“post fi x表达式后跟方括号[]中的表达式是下标 指定数组对象的元素。下标运算符[]的定义 是E1 [E2]与(*((E1)+(E2)))“
相同来自ISO / IEC 9899:201x委员会草案 - 2011年4月12日
所以arr [7]完全合法,7 [arr]也是如此。它是一个合法的表达并不意味着它指的是您的进程有权访问的内存位置,或者您想要的内存位置。
答案 1 :(得分:3)
以下陈述
extern char arr[];
是一个带有外部链接的声明,并说arr
的数组类型为char
,这意味着arr
可能有不完整的类型。
根据“6.7声明”(n1570):
7如果声明对象的标识符没有链接,则对象的类型应为 在其声明者的末尾完成,或者如果它有一个,则在其init-declarator的末尾完成 初始化;在函数参数(包括原型)的情况下,它是经过调整的 类型(见6.7.6.3),需要完整。
arr[7]
等于*(arr + 7)
,arr
需要一种“指向完整对象类型的指针”,arr
的类型将从“转换为”在这种情况下,char
“数组”指向char
的指针。
根据“6.3.2.1 Lvalues,数组和函数指示符”(n1570):
3除非它是
sizeof
运算符,_Alignof
运算符或者&
运算符的操作数。 一元{{1}}运算符,或者是用于初始化数组的字符串文字,一个包含的表达式 type''type of type''转换为类型为''指向type'的指针的表达式,指向数组对象的初始元素,而不是左值。
答案 2 :(得分:3)
引用WG14/N1124 Committee Draft May 6, 2005 ISO/IEC 9899:TC2
6.2.5类型
[22]未知大小的数组类型是不完整类型。它是 对于该类型的标识符,通过指定a中的大小来完成 后来申报(内部或外部联系)。
extern char arr[];
应为不完整类型。
6.5.2.1数组下标
[2]后缀表达式,后跟方括号中的表达式 []是数组对象元素的下标。该 下标运算符[]的定义是E1 [E2]与...相同 (*((E1)+(E2)))。由于适用于的转换规则 binary +运算符,如果E1是数组对象(等效于指针 到数组对象的初始元素),E2是一个整数, E1 [E2]表示E1的第E2个元素(从零开始计数)。
func(arr[7]); /* or func(7[arr]); */与
相同
func( *(arr + 7) ); /* Memory for arr allocated in other module; */
6.7.5.2数组声明符
[4]如果大小不存在,则数组类型是不完整的类型。
[8]例2注意声明之间的区别
extern int * x;
extern int y [];
第一个声明x是指向int的指针;该 第二个声明y是一个未指定大小的int数组(一个 不完整的类型),其存储在其他地方定义。
x已完成,因为sizeof x已知。 y是不完整的,因为编译此单位时y的大小未知。
extern char arr[];
与
相同extern char *arr;
<强>脚注 [92] 强>
如果之前的无效指针操作(例如访问数组外部) bounds)产生了未定义的行为,后续的比较也是如此 产生不确定的行为。
附件J.2未定义的行为
- 数组下标超出范围,即使某个对象显然也是如此 可以使用给定的下标访问(如左值表达式) a 1 [7]给出a [4] [5]中的声明)(6.5.6)。
- 加法或 将指针减去或超出数组对象和 整数类型产生的结果指向数组之外 object,用作一元*运算符的操作数 评估(6.5.6)。
编译器应生成代码以访问arr
的7 th 元素(从0开始),如果arr
的定义不包含7+1
,即8个或更多元素,行为应为undefined。但只要链接的arr
具有足够的大小,代码就是可编译的并且会表现出明确定义的行为。
答案 3 :(得分:2)
对于不完整类型,您必须进行自己的内存管理和边界检查,这意味着您知道arr[7]
是否是有效位置。
由于此数组中的访问和索引位置是使用不完整类型的唯一方法。
例如,即使您知道已为arr[]
分配了足够的内存以适应arr = arr2[5]
,也无法使用完整类型的值(例如arr2
)初始化不完整类型arr
{{1}}您只能记忆或遍历每个广告位。