sizeof 应用于不完整数组类型的参数

Sizeof applied to parameter of incomplete array type

对于此代码:

int f(int x[])
{
    return sizeof x;
}

GCC 产生:

warning: 'sizeof' on array function parameter 'x' will return size of 'int *'

Clang 产生:

warning: sizeof on array function parameter will return size of 'int *' instead of 'int[]'

问题:如果 x 的类型不完整(因为大小不存在),那么它是否应该具有:

error: invalid application of 'sizeof' to incomplete type

额外:是否意味着 return size of 'int *' 是 GCC/Clang 扩展?

将数组传递给函数时,实际上是将其地址作为指针传递。在数组上使用 sizeof() 只会 return 指针的大小。它不会产生错误,因为 sizeof(int*) 是一个有效的操作

作为函数参数的数组实际上是一个指针。来自 C standard 关于函数声明符的第 6.7.6.3p7 节:

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

这意味着:

int f(int x[])
{
    return sizeof x;
}

与此完全相同:

int f(int *x)
{
    return sizeof x;
}

所以x确实类型完整,没有错误。 gcc 和 clang 都有助于生成警告,因为结果可能不是人们所期望的。

Question: if x has incomplete type (since the size is not present), then is it expected to have:

error: invalid application of 'sizeof' to incomplete type

是的,当人们试图确定不完整类型的大小时,这将是 gcc 的常见错误消息,但这不是示例代码中发生的情况。

在函数声明的参数列表中,所有声明为数组类型的参数——包括不完整的数组类型——都被调整为具有相应的指针类型。这在 C17 6.7.6.3/7 中有描述:

A declaration of a parameter as “array of type” shall be adjusted to “qualified pointer to type”, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. [...]

这是源代码语义的问题,而不是运行时转换,尽管它与数组 values 自动转换为运行时发生的指针的自动转换相吻合(在原则)。

Extra: does it mean that return size of 'int *' is a GCC/Clang extension?

没有。警告消息描述了标准 C 的语义(永远如此)。

对于它的价值,当我计划访问参数时,我倾向于更喜欢您示例中的形式,就好像它指向数组的第一个成员(通过使用 [] 对其进行索引或执行指针算术)。特别是,我总是将 main 的 two-parameter 签名写为:

int main(int argc, char *argv[]);

尽管出现,您的 f 函数的 x 参数 不是 不完整类型。它是一个指针 (int*),因为 any 数组,当用作函数的声明参数时,在语法上等同于指向数组第一个元素的指针。

因此,您的 sizeof x 表达式的操作数是一个完整类型(指向 int 的指针); GNU 和 Clang 编译器给出的警告仅仅是 'reminding' 你这个 so-called 数组到指针的“衰减”。

到'verify'前面提到的等价,添加函数的前向声明,使用int* x作为形参——会有(或应该是) 没有进一步的警告:

int foo(int* x); // Foward declaration

int foo(int x[]) // Definition - No parameter type conflict
{
    return sizeof x ;
}