根据 C 标准的默认参数提升
Default argument promotions according to C standards
我正在阅读有关默认参数提升的 C 标准,并且对很多要点感到困惑。 This 问题以适当的方式显示了我有疑问的所有段落。
首先在第 6 段第 3 点中,它说如果原型以省略号结尾,则行为未定义。现在我的疑问是,如果我们谈论 printf
,它的原型也以省略号结尾,但它的行为不是未定义的,实际上它遵循第 6 段的第 1 点。标准在这里试图解释什么?进一步说,如果 提升后参数的类型与参数的类型不兼容,则行为未定义 .. 现在我怀疑是否已经在中声明了参数函数原型为什么首先要提升参数。
第6段第4点说提升后的参数类型与提升后的参数类型不兼容,行为未定义。在这里,提到函数没有原型,那么他们到底在谈论什么参数呢?以及如何提升参数。我只研究过参数提升。
比起第 7 段第 1 点,这一行是什么意思:将每个参数的类型作为其声明类型的非限定版本。
我真的很难理解这一切。如果您能用适当的例子一一解释所有要点,那将非常有帮助。我不是英语母语人士,如果我对某些标准的观点有误解,请指出错误。
在 C 1999 条款 6.5.2.2 第 6 段中,该问题中标记为 3 的项目旨在用标记为 1 的项目进行解释:如果 调用表达式 使用类型没有原型,并且 调用的函数 是用以省略号结尾的原型定义的,或者提升的参数类型与参数类型不兼容,则行为未定义。
所以这并不是说您不能使用省略号,只是说调用函数的表达式中使用的函数类型与定义函数时使用的函数类型之间可能存在冲突。
示例:
文件 Caller.c 包含:
void foo(); // No prototype (parameter types are not declared).
int main(void)
{
foo(3, 4);
}
文件 Function.c 包含:
void foo(int x,...) // Prototype (parameter types are declared) and has ellipsis.
{
}
该行为是未定义的,因为 foo
就像 void foo()
一样被调用,但它是用 void foo(int x,...)
定义的。这种不匹配不应该出现在现代实践中,因为在没有原型的情况下声明函数是旧式的。 C仍然支持它,所以旧的源代码仍然可以编译,但新的源代码不应该使用它。只要总是在函数声明和函数定义中声明参数类型,那么这种情况就永远不会发生。
第7段中,“将每个参数的类型取为其声明类型的非限定版本”的意思是忽略限定符(const
, volatile
, restrict
,或 _Atomic
)。这意味着可以为 const int
参数传递 int
参数,依此类推。
我正在阅读有关默认参数提升的 C 标准,并且对很多要点感到困惑。 This 问题以适当的方式显示了我有疑问的所有段落。
首先在第 6 段第 3 点中,它说如果原型以省略号结尾,则行为未定义。现在我的疑问是,如果我们谈论 printf
,它的原型也以省略号结尾,但它的行为不是未定义的,实际上它遵循第 6 段的第 1 点。标准在这里试图解释什么?进一步说,如果 提升后参数的类型与参数的类型不兼容,则行为未定义 .. 现在我怀疑是否已经在中声明了参数函数原型为什么首先要提升参数。
第6段第4点说提升后的参数类型与提升后的参数类型不兼容,行为未定义。在这里,提到函数没有原型,那么他们到底在谈论什么参数呢?以及如何提升参数。我只研究过参数提升。
比起第 7 段第 1 点,这一行是什么意思:将每个参数的类型作为其声明类型的非限定版本。
我真的很难理解这一切。如果您能用适当的例子一一解释所有要点,那将非常有帮助。我不是英语母语人士,如果我对某些标准的观点有误解,请指出错误。
在 C 1999 条款 6.5.2.2 第 6 段中,该问题中标记为 3 的项目旨在用标记为 1 的项目进行解释:如果 调用表达式 使用类型没有原型,并且 调用的函数 是用以省略号结尾的原型定义的,或者提升的参数类型与参数类型不兼容,则行为未定义。
所以这并不是说您不能使用省略号,只是说调用函数的表达式中使用的函数类型与定义函数时使用的函数类型之间可能存在冲突。
示例:
文件 Caller.c 包含:
void foo(); // No prototype (parameter types are not declared).
int main(void)
{
foo(3, 4);
}
文件 Function.c 包含:
void foo(int x,...) // Prototype (parameter types are declared) and has ellipsis.
{
}
该行为是未定义的,因为 foo
就像 void foo()
一样被调用,但它是用 void foo(int x,...)
定义的。这种不匹配不应该出现在现代实践中,因为在没有原型的情况下声明函数是旧式的。 C仍然支持它,所以旧的源代码仍然可以编译,但新的源代码不应该使用它。只要总是在函数声明和函数定义中声明参数类型,那么这种情况就永远不会发生。
第7段中,“将每个参数的类型取为其声明类型的非限定版本”的意思是忽略限定符(const
, volatile
, restrict
,或 _Atomic
)。这意味着可以为 const int
参数传递 int
参数,依此类推。