`void foo(int a[static 0]);` 有效吗?

tst*_*isl 4 c c99 language-lawyer

以下函数是否严格符合C99?

void foo(int a[static 0]) {
  (void)a;
}
Run Code Online (Sandbox Code Playgroud)

GCC 和 Clang 都会发出有关使用零大小数组的警告,但我认为这个警告是不合理的。AFAIK,6.7.6.3p7告诉static关键字指示指针a应该指向至少零个元素,任何具有确定值的指针都可以轻松满足这一要求。

此外,在以下情况下是否可以调用这样的函数:

int i;
foo(NULL);
foo(&i);
foo(&i + 1);
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 5

\n

AFAIK,6.7.6.3p7告诉static关键字表明指针a应该指向至少零个元素,\xe2\x80\xa6

\n
\n

6.7.6.3 7 并不是唯一适用的规则。

\n

如您所知,声明为数组的参数会自动调整为指针。但在调整之前,它是一个声明为数组的参数。数组声明符的规则之一是 6.7.6.2 1 中的约束:

\n
\n

除了可选的类型限定符和关键字 static 之外, and[]可以分隔表达式 或*。如果它们分隔表达式(指定数组的大小),则该表达式应具有整数类型。如果表达式是常量表达式,则其值应大于零\xe2\x80\xa6

\n
\n

即使满足 6.7.6.3 7,违反 6.7.6.2 1 也会违反约束条件。

\n
\n

\xe2\x80\xa6 指向至少零个元素,任何具有确定值的指针都可以轻松满足这一要求。

\n
\n

不它不是。首先,空指针不指向至少零个元素,因为它不指向任何东西。

\n

其次,指针不仅需要指向至少零个元素,而且还需要指向至少具有零个元素的数组的第一个元素。任何至少有零个元素的数组都至少有一个元素,因为 6.2.5 20 将数组类型定义为 \xe2\x80\x9c 具有特定成员对象类型\xe2\x80\x9d 的连续分配的非空对象集。因此,它是一个数组这一事实就意味着它至少有一个元素。

\n

因此,即使声明int a[static 0]a也必须至少指向一个int

\n


Lun*_*din 5

这是不合规的,因为数组的大小不能为 0。因此也不是“至少为 0”。

C17 6.7.6.2 强调我的:

约束条件

除了可选的类型限定符和关键字之外static,[ 和 ] 还可以分隔表达式或 *。如果它们分隔表达式(指定数组的大小),则该表达式应具有整数类型。如果表达式是常量表达式,则其值应大于零。

(在 C99 中,相同的文本位于 6.7.5.2 下面)