【问题标题】:C array/pointer declaration syntax quizC 数组/指针声明语法测验
【发布时间】:2018-09-18 22:12:21
【问题描述】:

我以为我了解 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 的指针的指针”,所以我希望在分配时需要一个“&”。为什么这不是必需的?

实际上下面的原型也可以工作(与上面相同的函数体):

int sum(const int buf[const], int len)

现在看起来更加清楚的是,与“buf”的声明相比,“p”的声明增加了一级指针重定向。仍然......分配工作正常,无需任何“&”。谁能解释一下?

【问题讨论】:

  • sum怎么叫?
  • 在你的例子中,'p' 变成了一个指向整数数组的指针,知道这个奥斯卡应该更有意义。
  • @Lundin:是的,我应该仔细看看,你是对的。我删除了我的 cmets。
  • 我在问题中添加了“语言律师”标签。当您对不一定具有实际生产质量的代码有疑问时,此标记很有用,但当您仍想知道行之间发生了什么时。
  • 请不要再磕磕绊绊了。你被很多垃圾绊倒了:(

标签: c syntax language-lawyer declaration c99


【解决方案1】:

首先,请注意这段代码不是好的做法。指针转换看起来很可疑且不寻常,尤其是它抛弃了 const 限定符,这是不好的做法。 (虽然一开始就将参数声明为 ...* const buf 是很可疑的。)

这确实有效。但是怎么做呢?

存在从(限定的)int 指针到 int 数组指针的指针转换。鉴于这两种指针类型没有不同的表示或不同的对齐方式(极不可能但理论上可能),指针转换本身是可以的(根据 C11 6.3.2.3/8)。

那么重要的是数据的有效类型,它是int 的(数组)。有效类型是一个正式的 C 术语,用于确定实际存储在某个位置的类型,无论用于访问的指针类型如何。只要通过与存储在那里的有效类型兼容的指针类型访问数据,代码就应该可以正常工作。

这很好的正式原因是 C11 6.5/7(“严格的别名规则”):

一个对象的存储值只能由具有以下之一的左值表达式访问 以下类型:
— 与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
/--/
— 聚合或联合类型,其中包括上述类型之一 成员

其中“聚合”是用于数组和结构的 C 标准乱码。如果我们通过数组类型的表达式访问数据,其中数组元素类型是与实际类型兼容的类型/限定类型,在这种情况下int,一切都很好。

至于它是如何工作的,它只是简单地取消引用一个数组指针。 p = (const int(*)[]) buf; 说“威胁存储在此变量中的内容作为指向整数数组的指针(并且限定符该死)”。然后(*p)[n] 获取数组指针,取消引用它以获取实际数组,然后使用数组索引。

p = buf 没有强制转换在这里给出编译器警告

如果你用gcc -pedantic-errors 编译你会得到一个更正确的错误。指针类型不兼容,因此编译器必须在此处生成诊断消息 - 因为p = buf 不是有效的 C。

p = (const int(*)[]) &amp;buf; // 不起作用!段错误!

这是因为存储在 &amp;buf 的不是 int 数组,它只是指针 buf 本身,可能作为函数的参数分配在堆栈上。

【讨论】:

  • 如果您添加一个粗体警告代码是有效的,那将是一件好事,尽管没有人应该写。程序员应该专注于编写没有诊断的清晰代码编译,启用所有推荐的警告,并且没有不合理的强制转换只是为了让编译器静音。
  • @Olaf 好点,我添加了一个警告。我怀疑代码的原作者可能是一些C语言知识水平相当高,但喜欢炫耀的diva。在我看来,这种程序员甚至比无知的新手更危险。
  • 这样的代码我见多了。我同意女主角,但不同意知识。我认为自己也有点像女主角,但我不会使用强制类型转换,除非我无法正确获取类型并准确了解它们的含义(在嵌入式编程中,您无法在硬件级别完全避免它们)。
  • @Olaf 我,我会把参数声明为 const int const const signed * const const restrict const buf 只是为了炫耀我的 leet diva 技能 :)
  • 那将违反 K.I.S.S 原则。好吧,我不是女主角。我可以忍受这一点。花更少的钱买鞋;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多