c - va_list 总是静态的吗?
问题描述
void va_test2(va_list ap2)
{
printf("va_test 2 : %d\n", va_arg(ap2, int));
}
void va_test1(const char* str, ...)
{
va_list ap1;
printf("%s\n", str);
va_start(ap1, str);
va_test2(ap1);
printf("va_test 1 : %d\n", va_arg(ap1, int));
va_test2(ap1);
}
int main(void)
{
va_test1("this is a test", 1, 2, 3);
}
result :
this is a test
va_test 2 : 1
va_test 1 : 2
va_test 2 : 3
result I expected:
this is a test
va_test 2 : 1
va_test 1 : 1
va_test 2 : 2
在我看来,在'va_test1'中初始化va_list'ap1'之后,它被复制到'va_test2'中的局部变量'ap2'中。
所以 va_arg(ap, int) 增加了 'va_test2' 中的 va_list 'ap2' 后,应该不会影响原来的 va_list 'ap1'。
但行为表明增加的参数实际上影响了“ap1”。
据我所知, va_arg 被定义
#define va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(T)) - _INTSIZEOF(T)))
这直接增加了发送的指针。
在我的结论中, va_list 无论在哪里声明,它似乎都是静态行为。
你能告诉我这是对的吗,为什么它表现出静态行为?
解决方案
va_list 总是静态的吗?
不它不是。它通常是本地的。
您的代码的行为未定义。通话后,va_test2(ap1);
您唯一可以做的ap1
就是打电话va_end(ap1)
。我们可以阅读C11 7.16p3:
[...] 对象 ap 可以作为参数传递给另一个函数;如果该函数调用带有参数 ap 的 va_arg 宏,则调用函数中 ap 的值是不确定的,应在进一步引用 ap 之前将其传递给 va_end 宏。
不过,您的代码的行为可以通过拒绝您的va_arg
定义来解释。您得到的行为与宏的显示定义不匹配,因为宏确实修改了变量的值(除非有隐藏的#define ap *ap
:),因此拒绝该定义将是前进的方式。
据我所知, va_arg 被定义
#define va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(T)) - _INTSIZEOF(T)))
我会说,很可能不是。如果您在 x86 架构上,则使用不同的寄存器传递不同的数据类型,如x86 abi所指定的(例如,请参阅第 21 页和第 52 页周围的整个部分)(请参阅此答案)。该定义很可能适用于一些有限的情况。如今,va_arg
通常是一些编译器魔法,比如gcc/stdarg.h __builtin_va_arg。
va_list
如果是数组类型或指向堆栈上数据的指针,则可以解释该行为。x86
它是一个结构的数组,如上面的 abi 中所定义。
// cross my fingers these are right
typedef int va_list[1];
#define va_start(ap, a) (*ap = (int*)&a);
#define va_arg(ap, t) (*(t*)((*ap += _INTSIZEOF(T)) - _INTSIZEOF(T)))
因为你的代码的行为没有定义,编译器实现者只是不关心这些代码的行为——它可以以任何方式表现。因此,你不能result I expected:
——你不能从这样的代码中期待任何东西——通常会期待鼻恶魔产生。
推荐阅读
- reactjs - react 在初始化期间返回未定义的键“mods”的切片缩减器。(还原)
- python - tkinter gui 在点击时设置文本
- caching - 自定义域重定向到 firebase 中的 index.html
- npm - npm install 不工作 npm ERR!代码 EPERM npm 错误!系统调用 mkdir npm ERR!路径 C:\Users\avtar~saini npm ERR! 错误号-4048
- apache-kafka - Kafka生产者代码将在事件产生时由哪个团队处理
- python - 从 BASE64 文件中获取文件类型
- python - 无法弄清楚 NameError
- python - 使用条件 pandas 删除行
- javascript - 从 AngularFireAuth 隐藏控制台中的错误
- csv - 如何在 csv 文件中将一行的两列与另一行的 6 列合并?