如何解决C99 中与调整参数相关的未定义行为
我不理解 C99 标准中的以下未定义行为:
函数定义中调整后的参数类型不是对象 类型 (6.9.1)
从标准来看,函数的参数需要在两种情况下进行调整:
- 一个数组被调整为一个指针,
- 并且将函数调整为指向函数的指针。
在第二种情况下,函数的调整参数确实不会是对象(据我所知标准区分对象和函数):
一个标识符可以表示一个对象;一个函数;标签或成员 结构、联合...
您能否澄清这一点并提供此类 UB 的示例?
解决方法
C 标准的第一个引用是不正确的。听起来像
——函数定义中调整后的参数类型不是 完整的对象类型 (6.9.1)
那是你省略了 complete
这个词。
例如,在一个与其定义不同类型的函数声明中,您可以指定一个不完整的对象类型,如
void f( size_t,size_t,int [][*] );
在这个函数声明中,第三个参数的声明不是一个完整的对象类型,因为数组元素的大小是未知的。
这是一个演示程序
#include <stdio.h>
void f( 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,int [][*] );
void g( size_t m,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,a );
return 0;
}
它的输出是
0 1 2
3 4 5
这里在程序中声明了这两个函数
void f( size_t,int [][*] );
和
void g( size_t,int [][*] );
有一个对象类型不完整的参数声明。
你不能使用这样的声明,例如它的定义是相同的类型
void f( size_t m,int a[][*] )
{
// ...
}
因为将第三个参数调整为指针后,编译器无法确定指针类型。即指针将具有不完整的对象类型 int ( * )[]
。
正如评论中所指出的,标准中的文字在 C11 中得到了更正。现在显示为 (C11 J.2):
— 函数定义中调整后的参数类型不是完整的对象类型 (6.9.1)。
这更有意义。
然而,我想不出一个在函数定义的参数中使用不完整对象类型的例子,它可以编译而不会出错。我能想到的是,也许有些编译器允许未使用的参数具有不完整的对象类型。
正如@Lundin 在评论中指出的那样,附录 J 是信息性的,而不是标准的规范部分。在标准规范部分中引用的第 6.9.1 节的文本中也进行了更正。 6.9.1/7最后一句的最后一句从“结果类型应该是一个对象类型”改为“结果类型应该是一个完整的对象类型” em>.
@Lundin 还指出,在函数定义中,不完整类型的调整参数类型违反了 C11 6.7.6.3/4 (C99 6.7.5.3/4) 的约束:
调整后,作为函数定义一部分的函数声明符中的参数类型列表中的参数不应具有不完整的类型。
这列在“约束”下,因此需要翻译程序以产生至少一个诊断。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。