C99 中与调整参数相关的未定义行为

Gui*_*ean 7 c c99 undefined-behavior language-lawyer implicit-conversion

我不明白 C99 标准中的以下未定义行为:

函数定义中的调整参数类型不是对象类型 (6.9.1)

从标准来看,函数的参数需要在两种情况下进行调整:

  • 一个数组被调整为一个指针,
  • 并且将函数调整为指向函数的指针。

在第二种情况下,函数的调整参数确实不是对象(据我所知,标准区分了对象和函数):

标识符可以表示一个对象;一个函数;一个标签或一个结构的成员,联合...

您能否澄清这一点并提供此类 UB 的示例?

Vla*_*cow 5

C 标准的第一个引用是不正确的。这听起来像

\n
\n

\xe2\x80\x94 函数定义中调整后的参数类型不是完整的对象类型(6.9.1)

\n
\n

那就是你漏掉了这个词complete

\n

例如,在与其定义类型不同的函数声明中,您可以指定不完整​​的对象类型,例如

\n
void f( size_t, size_t, int [][*] );\n
Run Code Online (Sandbox Code Playgroud)\n

在此函数声明中,第三个参数的声明不是完整的对象类型,因为数组元素的大小未知。

\n

这是一个演示程序

\n
#include <stdio.h>\n\nvoid f( size_t, size_t, int [][*] );\n\nvoid f( size_t m, size_t n, int a[][n] )\n{\n    for ( size_t i = 0; i < m; i++ )\n    {\n        for ( size_t j = 0; j < n; j++ )\n        {\n            a[i][j] = n * i + j;\n        }\n    }\n}\n\nvoid g( size_t, size_t, int [][*] );\n\nvoid g( size_t m, size_t n, int a[][n] )\n{\n    for ( size_t i = 0; i < m; i++ )\n    {\n        for ( size_t j = 0; j < n; j++ )\n        {\n            printf( "%d ", a[i][j] );\n        }\n        putchar( '\\n' );\n    }\n}\n\nint main(void) \n{\n    size_t m = 2, n = 3;\n    int a[m][n];\n    \n    f( m, n, a );\n    g( m, n, a );\n    \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它的输出是

\n
0 1 2 \n3 4 5 \n
Run Code Online (Sandbox Code Playgroud)\n

在程序中这两个函数声明

\n
void f( size_t, size_t, int [][*] );\n
Run Code Online (Sandbox Code Playgroud)\n

\n
void g( size_t, size_t, int [][*] );\n
Run Code Online (Sandbox Code Playgroud)\n

具有不完整对象类型的参数声明。

\n

您不能使用这样的声明,即其定义位于同一类型,例如

\n
void f( size_t m, size_t n, int a[][*] )\n{\n    // ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n

因为将第三个参数调整为指针后,编译器无法确定指针类型。也就是说指针将具有不完整的对象类型int ( * )[]

\n

  • 与其责怪OP,不如说C99版本省略了“完整”这个词。 (2认同)