不完整数组类型的p [0]和*p的等价性

Oli*_*rth 19 c arrays gcc pointers incomplete-type

考虑以下代码(它是由于此讨论而产生的):

#include <stdio.h>

void foo(int (*p)[]) {          // Argument has incomplete array type
    printf("%d\n", (*p)[1]);
    printf("%d\n", p[0][1]);    // Line 5
}

int main(void) {
    int a[] = { 5, 6, 7 };
    foo(&a);                    // Line 10
}
Run Code Online (Sandbox Code Playgroud)

GCC 4.3.4 抱怨错误消息:

prog.c: In function ‘foo’:
prog.c:5: error: invalid use of array with unspecified bounds
Run Code Online (Sandbox Code Playgroud)

在GCC 4.1.2相同的错误消息,并且似乎是不变的-std=c99,-Wall,-Wextra.

所以它对表达式不满意p[0],但它很满意*p,尽管这些(理论上)应该是等价的.如果我注释掉第5行,代码会编译并执行我"期望"(显示6)的内容.

大概有以下之一是真的:

  1. 我对C标准的理解是不正确的,这些表达式并不相同.
  2. GCC有一个错误.

我把钱放在(1)上.

问题:任何人都可以详细说明这种行为吗?

澄清:我知道可以通过在函数定义中指定数组大小来"解决"这个问题.那不是我感兴趣的东西.


对于"奖励"积分:任何人都可以通过以下消息拒绝第10行时确认MSVC 2010是错误的吗?

1><snip>\prog.c(10): warning C4048: different array subscripts : 'int (*)[]' and 'int (*)[3]'
Run Code Online (Sandbox Code Playgroud)

Dan*_*her 14

n1570的6.5.2.1节,数组下标:

约束

其中一个表达式应具有类型''指向完整对象类型'的指针,另一个表达式应具有整数类型,结果具有类型''type''.

所以标准禁止表达式p[0]if if p是指向不完整类型的指针.对于间接运算符没有这样的限制*.

但是,在标准的旧版本/草稿中(n1256和C99),该段落中没有"完整"一词.在标准程序中没有涉及任何方式,我只能猜测这是一个突破性的变化还是一个疏忽的纠正.编译器的行为表明后者.这是因为p[i]每个标准都是相同的,*(p + i)并且后一个表达式对于指向不完整类型的指针没有意义,所以为了p[0]工作如果p是指向不完整类型的指针,则需要一个明确的特殊情况.

  • @Oli:我怀疑````运算符的定义隐含在`+`中; 显然`+`需要指向的类型才能完全正常运行,但我似乎无法找到使这个显式明确的文本...... (3认同)
  • *''指向完整对象类型的指针''*和*''指向对象类型''*的指针实际上是规范等价的:§6.2.5表示类型被分区为*对象类型*,*函数类型*和*不完整类型*.所以改变只是一个澄清 - 它没有改变规范效应. (2认同)

Ben*_*Ben 5

我的 C 有点生疏,但我的理解是,当你有一个int (*p)[]这样的:

(*p)[n]
Run Code Online (Sandbox Code Playgroud)

说“取消引用p以获得一个整数数组,然后取第 n 个”。这似乎很自然地得到了很好的定义。而这:

p[n][m]
Run Code Online (Sandbox Code Playgroud)

说“取 p 中的第 n 个数组,然后取该数组的第 m 个元素”。这似乎根本没有明确定义;您必须知道数组有多大才能找到第 n 个数组的开始位置。

可能适用于 n = 0 的特定特殊情况,因为无论数组有多大,第 0 个数组都很容易找到。您只是发现 GCC 无法识别这种特殊情况。我不知道详细的语言规范,所以我不知道这是否是一个“错误”,但我个人在语言设计方面的品味是p[n][m]应该有效还是无效,而不是在n静态已知时它应该有效为 0 而不是其他。

*p <===> p[0]真正从语言规范的明确规则,或只是一个观察?在我编程时,我不认为取消引用和零索引是相同的操作。

  • 语言规范规定`p[0] === *(p + 0)`。如果所指向类型的大小是已知的,那当然与 `*p` 相同,但是对于未知的大小,它需要一个特殊的 0 才能工作。 (2认同)