为什么 [static AND] 在编译时不强制执行?
Why is [static N] not enforced at compile-time?
C99在函数参数中增加了static(只在函数定义中有意义,不在声明中):
void func( int a[static 10] )
{
if ( a == NULL )
{ /* this branch can be optimized out */ }
printf("%d", a[-1]); /* causes UB */
}
然而,其含义在C11 6.7.6.3/7中被定义为语义,而不是约束,这意味着如果函数调用不正确,编译器不应发出诊断。事实上,编译器绝不能中止编译,除非它能证明UB 是在所有分支中引起的。例如:
int main()
{
func(NULL); // UB
int b[9];
func(b); // UB
}
为什么标准没有将此作为约束(因此需要诊断)?
第二个问题:为什么static
在原型(6.7.6.3/13)中被忽略,而不是作为函数签名的一部分?允许原型包含它但函数体不包含它似乎具有误导性,反之亦然。
因为在所有情况下都无法在编译时检测到违规。
例如,参数可以是指向分配给 malloc()
的数组的初始元素的指针。编译器通常无法确定数组的大小。如果参数是一个指针对象,编译器也不能检测它是否为 null。
此功能的主要目的不是强制限制调用,而是启用优化。编译器可能假设参数指向指定长度数组的初始元素。在某些情况下,这可以实现更好的代码生成。
但是编译器肯定可以对它们可以检测到的情况发出非致命警告。标准中没有暗示不应发出此类警告。
C99在函数参数中增加了static(只在函数定义中有意义,不在声明中):
void func( int a[static 10] )
{
if ( a == NULL )
{ /* this branch can be optimized out */ }
printf("%d", a[-1]); /* causes UB */
}
然而,其含义在C11 6.7.6.3/7中被定义为语义,而不是约束,这意味着如果函数调用不正确,编译器不应发出诊断。事实上,编译器绝不能中止编译,除非它能证明UB 是在所有分支中引起的。例如:
int main()
{
func(NULL); // UB
int b[9];
func(b); // UB
}
为什么标准没有将此作为约束(因此需要诊断)?
第二个问题:为什么static
在原型(6.7.6.3/13)中被忽略,而不是作为函数签名的一部分?允许原型包含它但函数体不包含它似乎具有误导性,反之亦然。
因为在所有情况下都无法在编译时检测到违规。
例如,参数可以是指向分配给 malloc()
的数组的初始元素的指针。编译器通常无法确定数组的大小。如果参数是一个指针对象,编译器也不能检测它是否为 null。
此功能的主要目的不是强制限制调用,而是启用优化。编译器可能假设参数指向指定长度数组的初始元素。在某些情况下,这可以实现更好的代码生成。
但是编译器肯定可以对它们可以检测到的情况发出非致命警告。标准中没有暗示不应发出此类警告。