可变数量的参数
Variable numbers of arguments
我有几个关于变量数量的问题:
-
为什么
va_start
、va_arg
和va_end
被定义为宏而不是函数? -
va_start
是如何工作的?它是否有权访问函数调用堆栈,并遍历堆栈直到找到最后一个指定的参数?
它们为什么是宏的基本原理在7.15
变量自变量部分的国际标准——编程语言——C的基本原理中有介绍,它说:
va_start和va_arg必须作为宏存在,因为va_start使用的参数是通过name传递,va_arg使用一个参数,该参数是数据类型的名称。
这篇文章如何可变参数列表在C中工作更详细地介绍了为什么,并给出了一个可能的x86实现:
typedef char *va_list;
#define va_start( list, param ) (list = (va_list)(¶m + sizeof( param )))
#define va_arg( list, type ) (*(type *)((list += sizeof( type )) - sizeof( type ))
在C++中,你有很多其他的替代方案和C++中可变数量的参数?可能涵盖了所有这些。
实际上va_end
不需要作为宏来实现,我认为va_start也不需要(您只需要将&
添加到参数中就可以向它们传递指针)va_end
和va_start
必须作为宏来实现,因为不能在所有情况下都使用&
,正如评论中所指出的那样。
va_arg
必须作为宏来实现,因为您需要提供一个类型作为参数,而没有宏是无法做到这一点的。
va_start
按照您的假设工作:您给它第一个参数,它可以根据该参数的大小计算其他参数的位置,因为它们在堆栈上都是连续的。
它只需启动指向第一个参数(传递给va_start
)末尾的va_list
,并在每次使用va_arg
时添加下一个参数的大小。
va_start
、va_arg
和va_end
通常必须在变量函数的上下文中执行才能完成它们的工作,因此使它们成为函数会使它们变得更加复杂,或者(在某些情况下)完全不可能实现。
它如何工作的细节留给实现。在典型的情况下,变元函数的参数将从左向右推,因此第一个参数将最接近堆栈的顶部。为了达到这个目的,va_arg
只需要知道堆栈帧的基本结构,比如返回地址有多大(顶部参数通常就在它旁边)。
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 使用指向成员的指针将成员函数作为参数传递
- 没有名称的C++模板参数
- 如何将enable-if与模板参数和参数包一起使用