【发布时间】:2019-05-13 14:18:45
【问题描述】:
我注意到 C 编译器(gcc、clang、tinycc)允许我将指向较大数组的指针分配给指向较小 VLA 的指针而不会发出警告:
#include <stdio.h>
#if !__TINYC__
void take_vla(int N, char const X[1][N]) { printf("%zd\n", sizeof(*X)); }
#endif
int main()
{
static char bigarray[]="0123456789abcdefghijklmnopqrstuvwxyz";
//VLA
int n = 3;
char const (*subarray2)[n]=&bigarray;
//char const (*subarray3)[(int){3}]=&bigarray; //VLA but clang doesn't see it as such (a bug, I guess)
#if !__TINYC__
take_vla(3,&bigarray);
take_vla(3,&"abcdefg");
#endif
#if 0
char const (*subarray1)[3]=&bigarray; //-Wincompatible-pointer-types
#endif
}
这是符合 C 的吗?为什么?
【问题讨论】:
-
在 C 中,指针只是 CPU 的数字,没有关于它们指向什么的额外信息,并且该语言也没有定义任何元数据,所以没关系关于它所指向的大小,只是类型相同(这是编译器的东西而不是 CPU 的东西)。
-
在您的
subarray2声明中,n仅用于地址计算,不会导致存储分配,例如在subarray2++中,将添加n字符的大小。可以认为,当分配的指针指向与n大小不同的对象时,编译器可能会发出警告,但是,这将是运行时问题,通常不是编译时间问题。 -
@Skizz 是的,但是对于 C 的类型系统,它从未如此简单,不是吗。尝试将最后一个
#if 0更改为#if 1并且您会收到有关该分配的警告(较大的普通旧数组到较小的普通旧数组)。如果“指针只是数字”无关紧要,但对于编译器来说它确实如此。 -
@Skizz:在 C 中,指针不只是指向 CPU 的数字,这既是因为它们具有类型信息(这会影响 C 中的指针运算),也是因为 they are abstractions .
-
代码不严格符合 C,因为赋值运算符的约束 (C 2018 6.5.16.1 1) 说这两个指针必须是指向兼容类型版本的指针,以及可能指向的规则两种兼容的数组类型(6.2.7 3)在不同指定长度的数组的情况下不提供。 (在这种情况下,“指定”包括通过评估其大小表达式确定的长度。)
标签: c arrays language-lawyer c11