我以为我理解C数组,指针和数组指针是如何工作的,但现在我偶然发现了一段我不理解的工作代码:
int sum(const int * const buf, int len)
{
int result = 0;
const int (*p)[];
int n;
p = (const int(*)[]) buf;
// p = buf without cast gives compiler warning here (but works)
// p = (const int(*)[]) &buf; // Doesn't work! Segfault!
for( n=0; n<len; n++)
{
result += (*p)[n];
}
return result;
}
这实际上有效。但是怎么样?问题是:从“buf”到“p”的分配如何工作?我认为这个p的声明类似于“指向指向int的指针”,所以我原本期望一个“&amp;”在任务中是必要的。为什么这没必要?
事实上,下面的原型也可以使用(上面有相同的功能体):
int sum(const int buf[const], int len)
现在似乎更清楚的是,与“buf”的声明相比,“p”的声明增加了一个指针重定向级别。仍然......分配工作正常,没有任何“&amp;”必要。有人可以解释一下吗?
答案 0 :(得分:2)
首先,请注意此代码不是好习惯。指针转换看起来很奇怪而且很不寻常,特别是它会抛弃const限定符,这是不好的做法。 (尽管如此,将参数声明为...* const buf
是非常可疑的。)
这实际上有效。但是如何?
有一个指针从(限定的)int指针转换为int数组指针。鉴于这两种指针类型没有不同的表示或不同的对齐(极不可能但理论上可行),指针转换本身就可以了(根据C11 6.3.2.3/8)。
重要的是数据的有效类型,它是({1}}的数组。有效类型是一个形式C术语,用于确定实际存储在某个位置的类型,无论用于访问的指针类型如何。只要通过与存储在那里的有效类型兼容的指针类型访问数据,代码就可以正常工作。
这很好的正式原因是C11 6.5 / 7(&#34;严格的别名规则&#34;):
对象的存储值只能由具有其中一个的左值表达式访问 以下类型:
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本,
/ - /
- 聚合或联合类型,其中包括上述类型之一 成员
在哪里&#34;聚合&#34;是阵列和结构的C标准乱码。如果我们通过数组类型的表达式访问数据,其中数组元素类型是与实际类型兼容的类型/限定类型,在这种情况下int
,一切都很好。
至于它如何工作,它只是取消引用一个数组指针。 int
表示&#34;威胁这个变量中存储的内容作为指向整数数组的指针(和限定词被诅咒)&#34;。然后p = (const int(*)[]) buf;
获取数组指针,取消引用它以获取实际数组,然后使用数组索引。
没有强制转换的
(*p)[n]
会在此处发出编译器警告
如果使用p = buf
进行编译,则会得到更正确的错误。指针类型不兼容,因此编译器必须在此处生成诊断消息 - 因为gcc -pedantic-errors
无效C.
p = buf
//没有用!段错误!
这是因为p = (const int(*)[]) &buf;
中存储的内容不是int数组,它只是指针&buf
本身,可能在堆栈上作为函数的参数分配。 / p>