C数组/指针声明语法测验

时间:2018-04-09 13:27:57

标签: c syntax language-lawyer declaration c99

我以为我理解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;”必要。有人可以解释一下吗?

1 个答案:

答案 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>