C99 中与调整参数相关的未定义行为
Undefined Behaviour in C99 related to adjusted parameters
我不理解 C99 标准中的以下未定义行为:
An adjusted parameter type in a function definition is not an object
type (6.9.1)
根据标准,函数的参数在两种情况下需要调整:
- 数组调整为指针,
- 并且函数被调整为指向函数的指针。
在第二种情况下,函数调整后的参数确实不是对象(据我所知标准区分对象和函数):
An identifier can denote an object; a function; a tag or a member of a
structure, union...
您能否阐明这一点并提供此类 UB 的示例?
正如评论中所指出的,标准中的文本已在 C11 中得到更正。现在是 (C11 J.2):
— An adjusted parameter type in a function definition is not a complete object type (6.9.1).
这更有意义。
但是,我想不出一个在函数定义的参数中使用不完整对象类型的示例,而该函数定义可以编译而不会出错。我能想到的是,也许某些编译器允许未使用的参数具有不完整的对象类型。
正如@Lundin 在评论中指出的那样,附录 J 是提供信息的,而不是标准的规范部分。在标准的规范部分中引用的第 6.9.1 节的文本中也进行了更正。 6.9.1/7 最后一句的最后一句从 "the resulting type shall be an object type" 更改为 "the resulting type shall be a complete对象类型.
@Lundin 还指出,在函数定义中,调整后的参数类型是不完整的类型是 C11 6.7.6.3/4 (C99 6.7.5.3/4) 的约束违规:
After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.
列在“约束”下,因此需要翻译程序以生成至少一个诊断。
C 标准的第一个引述不正确。听起来像
— An adjusted parameter type in a function definition is not a
complete object type (6.9.1)
那是你省略了complete
这个词。
例如,在与其定义类型不同的函数声明中,您可以指定一个不完整的对象类型,例如
void f( size_t, size_t, int [][*] );
在这个函数声明中,第三个参数的声明不是一个完整的对象类型,因为数组元素的大小是未知的。
这是一个演示程序
#include <stdio.h>
void f( size_t, size_t, int [][*] );
void f( size_t m, size_t n, int a[][n] )
{
for ( size_t i = 0; i < m; i++ )
{
for ( size_t j = 0; j < n; j++ )
{
a[i][j] = n * i + j;
}
}
}
void g( size_t, size_t, int [][*] );
void g( size_t m, size_t n, int a[][n] )
{
for ( size_t i = 0; i < m; i++ )
{
for ( size_t j = 0; j < n; j++ )
{
printf( "%d ", a[i][j] );
}
putchar( '\n' );
}
}
int main(void)
{
size_t m = 2, n = 3;
int a[m][n];
f( m, n, a );
g( m, n, a );
return 0;
}
它的输出是
0 1 2
3 4 5
这里在程序中声明了这两个函数
void f( size_t, size_t, int [][*] );
和
void g( size_t, size_t, int [][*] );
有一个对象类型不完整的参数声明。
你不能使用这样的声明,在同一类型是它的定义,例如
void f( size_t m, size_t n, int a[][*] )
{
// ...
}
因为编译器将第三个参数调整为指针后无法判断指针类型。即指针将具有不完整的对象类型 int ( * )[]
.
我不理解 C99 标准中的以下未定义行为:
An adjusted parameter type in a function definition is not an object type (6.9.1)
根据标准,函数的参数在两种情况下需要调整:
- 数组调整为指针,
- 并且函数被调整为指向函数的指针。
在第二种情况下,函数调整后的参数确实不是对象(据我所知标准区分对象和函数):
An identifier can denote an object; a function; a tag or a member of a structure, union...
您能否阐明这一点并提供此类 UB 的示例?
正如评论中所指出的,标准中的文本已在 C11 中得到更正。现在是 (C11 J.2):
— An adjusted parameter type in a function definition is not a complete object type (6.9.1).
这更有意义。
但是,我想不出一个在函数定义的参数中使用不完整对象类型的示例,而该函数定义可以编译而不会出错。我能想到的是,也许某些编译器允许未使用的参数具有不完整的对象类型。
正如@Lundin 在评论中指出的那样,附录 J 是提供信息的,而不是标准的规范部分。在标准的规范部分中引用的第 6.9.1 节的文本中也进行了更正。 6.9.1/7 最后一句的最后一句从 "the resulting type shall be an object type" 更改为 "the resulting type shall be a complete对象类型.
@Lundin 还指出,在函数定义中,调整后的参数类型是不完整的类型是 C11 6.7.6.3/4 (C99 6.7.5.3/4) 的约束违规:
After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.
列在“约束”下,因此需要翻译程序以生成至少一个诊断。
C 标准的第一个引述不正确。听起来像
— An adjusted parameter type in a function definition is not a complete object type (6.9.1)
那是你省略了complete
这个词。
例如,在与其定义类型不同的函数声明中,您可以指定一个不完整的对象类型,例如
void f( size_t, size_t, int [][*] );
在这个函数声明中,第三个参数的声明不是一个完整的对象类型,因为数组元素的大小是未知的。
这是一个演示程序
#include <stdio.h>
void f( size_t, size_t, int [][*] );
void f( size_t m, size_t n, int a[][n] )
{
for ( size_t i = 0; i < m; i++ )
{
for ( size_t j = 0; j < n; j++ )
{
a[i][j] = n * i + j;
}
}
}
void g( size_t, size_t, int [][*] );
void g( size_t m, size_t n, int a[][n] )
{
for ( size_t i = 0; i < m; i++ )
{
for ( size_t j = 0; j < n; j++ )
{
printf( "%d ", a[i][j] );
}
putchar( '\n' );
}
}
int main(void)
{
size_t m = 2, n = 3;
int a[m][n];
f( m, n, a );
g( m, n, a );
return 0;
}
它的输出是
0 1 2
3 4 5
这里在程序中声明了这两个函数
void f( size_t, size_t, int [][*] );
和
void g( size_t, size_t, int [][*] );
有一个对象类型不完整的参数声明。
你不能使用这样的声明,在同一类型是它的定义,例如
void f( size_t m, size_t n, int a[][*] )
{
// ...
}
因为编译器将第三个参数调整为指针后无法判断指针类型。即指针将具有不完整的对象类型 int ( * )[]
.