GNU99下一次性声明指向初始化int数组的指针问题(GCC5.2.0)
首先得说,你那个能正常运行的写法 int a1[] = {1, 2, 3, 4, 5}; int (*a)[] = &a1; 是完全合规的——先定义一个具名数组,再取它的地址赋值给指向数组的指针,这是标准C的操作,没毛病。
接下来咱们逐个分析那两个有问题的写法:
1. 为什么 int *why = (int p[2]) {1,2}; 会报错?
这个写法的语法完全搞错了。C语言里的强制类型转换只能写类型名,不能在转换里加变量名p。你应该是想利用GNU99支持的复合字面量特性,但用错了格式。
复合字面量的正确格式是(类型){初始化列表},不需要额外声明变量。如果你的需求是创建一个匿名的2元素int数组,让指针指向它的首元素,正确的写法应该是:
int *why = (int[2]){1, 2};
这样写的话,(int[2]){1,2}会创建一个匿名的int[2]数组,数组名会隐式转换成指向首元素的int*指针,正好能赋值给why。
你原来的写法里在类型里加了p[2],编译器根本看不懂这种语法,自然会抛出expected ')' before 'p'的错误——它以为你在写某种函数式转换,但语法完全不匹配。
2. 为什么 int (*b)[5]= (int(*)[5])&({11,2,3,5,6}); 会出警告?
这里的问题出在({11,2,3,5,6})上——这是GNU扩展的语句表达式,它的返回值是最后一个表达式的值,也就是6,而不是你以为的数组。所以你取&({11,2,3,5,6})实际上是取了临时值6的地址,然后强行转换成int(*)[5]类型,这不仅类型完全不匹配,而且语句表达式里前面的11,2,3,5都是逗号表达式的左操作数,没有任何实际作用,编译器自然会警告你left-hand operand of comma expression has no effect。
如果想创建一个匿名的5元素int数组,让指向数组的指针指向它,正确的复合字面量写法应该是:
int (*b)[5] = &(int[5]){11, 2, 3, 5, 6};
这里(int[5]){11,2,3,5,6}是一个复合字面量,代表匿名的int[5]数组,取它的地址&就得到了int(*)[5]类型的指针,和b的类型完美匹配,这样就不会有任何警告和错误了。
最后再划个重点:
- 复合字面量的核心格式是
(类型){初始化列表},别画蛇添足加变量名; - 语句表达式
({...})和复合字面量是两种不同的GNU扩展,别搞混了; - 要得到指向数组的指针,直接对数组类型的复合字面量取地址就行,类型一定要对应上。
内容的提问来源于stack exchange,提问作者yo3hcv

