Joh*_*itb 16 c c++ arrays variadic-functions
这个问题是关于vararg函数,以及省略号之前的最后一个命名参数:
void f(Type paramN, ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
Run Code Online (Sandbox Code Playgroud)
我正在阅读C标准,并发现va_start宏的以下限制:
参数parmN是函数定义中变量参数列表中最右边参数的标识符(恰好在......之前).如果参数parmN使用寄存器存储类,函数或数组类型声明,或者使用与应用默认参数提升后生成的类型不兼容的类型,则行为未定义.
我想知道为什么以下代码的行为未定义
void f(int paramN[], ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
Run Code Online (Sandbox Code Playgroud)
并且未定义以下内容
void f(int *paramN, ...) {
va_list ap;
va_start(ap, paramN);
va_end(ap);
}
Run Code Online (Sandbox Code Playgroud)
宏可以通过纯C代码实现.但纯C代码无法确定是否paramN声明为数组或指针.在这两种情况下,参数的类型都被调整为指针.功能类型参数也是如此.
我想知道:这个限制的理由是什么?在内部进行这些参数调整时,某些编译器是否存在实现此问题的问题?(C++也说明了相同的未定义行为 - 所以我的问题是关于C++的问题).
对寄存器参数或函数参数的限制可能类似于:
register存储类获取变量的地址.va_start()和/或va_arg()通过向地址添加一些固定数量来实现,paramN并且函数指针大于对象指针,则计算最终会va_arg()返回对象返回的错误地址.这似乎不是实现这些宏的好方法,但可能存在具有(甚至需要)此类实现的平台.我想不出阻止允许数组参数会出现什么问题,但是PJ Plauger在他的书"标准C库"中这样说:
对定义的宏施加的一些限制
<stdarg.h>似乎不必要地严重.对于某些实现,它们是.然而,每个都被引入,以满足至少一个严重的C实现的需要.
我想,很少有人比Plauger更了解C库的来龙去脉.我希望有人可以用一个实际的例子回答这个具体问题; 我认为这将是一个有趣的琐事.
新信息:
"国际标准的基本原理 - 编程语言 - C"说va_start():
该
parmN参数va_start旨在帮助实现者va_start完全用C语言编写一致的宏的定义,甚至使用前C89编译器(例如,通过获取参数的地址).对parmN参数声明的限制遵循允许这种实现的意图,因为如果参数的声明不符合这些限制,将&运算符应用于参数名称可能不会产生预期的结果.
这并不能帮助我限制数组参数.
这不是未定义的。请记住,当参数声明为 时int paramN[],实际参数类型仍将衰减为int* paramN立即(这在 C++ 中可见,例如,如果您应用于typeid)paramN。
我必须承认,考虑到您首先不能拥有函数或数组类型的参数(因为它们会指针衰减),我什至不确定规范中的这一点的用途。