1

我正在尝试使用 va_arg 在我的 GUI 库中创建一个通用工厂函数。当在同一个函数中传递 va_arg 两次时,它们传递相同的值而不是两个不同的值:

GUIObject* factory(enumGUIType type, GUIObject* parent, ...){
   va_list vl;
   va_start(vl, parent);
   ...
   label->SetPosition(va_arg(vl, int), va_arg(vl, int));
   va_end(vl);
   return finalObjectPointer;
}

factory(LABEL, theParent, 100,200); // Results in position 200:200

是什么导致了这种意外行为?

4

3 回答 3

6

编译器不保证按顺序评估参数。添加一些额外的局部变量并按顺序进行这两个赋值。

请参阅其他堆栈溢出帖子。

int v1 = va_arg(vl, int);
int v2 = va_arg(vl, int);

label->SetPosition(v1, v2);

要获得您所观察到的内容:两次完全相同的值 - 可能需要编译器错误堆积在未定义的评估顺序之上,或者在您的环境中 va_arg 的特定宏扩展的某些有趣方面。

于 2009-12-28T01:39:01.873 回答
6

va_arg是一个宏。隐藏在该宏后面的是实现定义,这意味着代替执行的操作很可能va_arg具有副作用。因此,va_arg在两个相邻序列点之间多次使用不是一个好主意。这可能是未定义的行为,这意味着任何事情都可能发生。看起来这正是您的情况,当您从va_arg.

即使在某些实现中没有未定义的行为,函数调用中的参数评估顺序也是未指定的,这意味着以您使用它们的方式使用任何“顺序读取器”不能保证按预期工作(无论您想要什么) .

于 2009-12-28T01:46:44.073 回答
2

在不同参数的评估之间没有序列点,因此在评估参数时修改相同的值(vl或它所指的东西)两次会导致未指定的行为。

va_arg更改 的内部状态vl以注册已处理的参数,并且在参数评估期间执行此操作两次时,未指定会发生什么。您的编译器及其使用的优化似乎导致两个相同的参数被传递。

于 2009-12-28T01:46:38.027 回答