[英]va_arg returning the wrong argument
With the following code va_arg is returning garbage for the second and third pass through vProcessType. 使用以下代码,va_arg将通过vProcessType返回第二次和第三次传递的垃圾。
// va_list_test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <tchar.h>
#include <cstdarg>
#include <windows.h>
void processList(LPTSTR str, ...);
void vProcessList(LPTSTR str, va_list args);
void vProcessType(va_list args, int type);
int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR a = TEXT("foobar");
int b = 1234;
LPTSTR c = TEXT("hello world");
processList(TEXT("foobar"), a, b, c);
return 0;
}
void processList(LPTSTR str, ...)
{
va_list args;
va_start(args, str);
vProcessList(str, args);
va_end(args);
}
void vProcessList(LPTSTR str, va_list args)
{
vProcessType(args, 1);
vProcessType(args, 2);
vProcessType(args, 1);
}
void vProcessType(va_list args, int type)
{
switch(type)
{
case 1:
{
LPTSTR str = va_arg(args, LPTSTR);
printf("%s", str);
}
break;
case 2:
{
int num = va_arg(args, int);
printf("%d", num);
}
break;
default:
break;
}
}
Is passing a va_list thing not allowed in this way? 是不是以这种方式传递了一个va_list的东西? The first call to va_arg inside vProcessType returns the expected string. 在vProcessType中第一次调用va_arg会返回预期的字符串。 The second and third time through this function it returns a pointer to the start of the first string, instead of the values expected. 第二次和第三次通过此函数返回指向第一个字符串开头的指针,而不是预期的值。
If I hoist the va_arg call to vProcessList, everything seems to work fine. 如果我将va_arg调用提升到vProcessList,一切似乎都能正常工作。 It only seems when I pass a va_list through a function that I'm getting this behaviour. 只有当我通过函数传递va_list时才会出现这种行为。
You're passing the same va_list
each time to vProcessType()
- in each call to vProcessType()
you're acting on the first va_arg
in the list. 您每次都将相同的va_list
传递给vProcessType()
- 在每次调用vProcessType()
您将对列表中的第一个va_arg
执行操作。
So you're always dealing with the TEXT("foobar")
parameter when calling vProcessType()
. 因此,在调用vProcessType()
时,您始终处理TEXT("foobar")
参数。
Also note that the standard has this to say about passing a va_list
to another function: 另请注意,标准有关于将va_list
传递给另一个函数的说法:
The object
ap
[of typeva_list
] may be passed as an argument to another function; 对象ap
[类型为va_list
]可以作为参数传递给另一个函数; if that function invokes theva_arg
macro with parameterap
, the value ofap
in the calling function is indeterminate and shall be passed to theva_end
macro prior to any further reference toap
. 如果该函数使用参数ap
调用va_arg
宏,则调用函数中的ap
值是不确定的,并且应该在进一步引用ap
之前传递给va_end
宏。
A foot note in the standard indicate that it's perfect OK to pass a pointer to a va_list
, so what you might want to do is have vProcessType()
take a pointer to the va_list
: 标准中的脚注表明将指针传递给va_list
是完美的,所以你可能要做的是让vProcessType()
获取指向va_list
的指针:
void vProcessType(va_list* pargs, int type);
When you pass the va_list
object to another function and that another function uses va_arg
on the corresponding parameter, that va_list
will have indeterminate value in the calling function when the control returns. 当您将va_list
对象传递给另一个函数并且另一个函数在相应参数上使用va_arg
时,该控件返回时该va_list
将在调用函数中具有不确定的值 。 The only thing you are allowed to do is to apply va_end
to that va_list
object. 您唯一可以做的是将va_end
应用于该va_list
对象。
This is how it is stated in the standard (7.15/3) 这就是标准中规定的方式(7.15 / 3)
If access to the varying arguments is desired, the called function shall declare an object (generally referred to as
ap
in this subclause) having typeva_list
. 如果需要访问变量参数,则被调用函数应声明类型为va_list
的对象(在va_list
条款中通常称为ap
)。 The objectap
may be passed as an argument to another function; 对象ap
可以作为参数传递给另一个函数; if that function invokes theva_arg
macro with parameterap
, the value ofap
in the calling function is indeterminate and shall be passed to theva_end
macro prior to any further reference toap
. 如果该函数使用参数ap
调用va_arg
宏,则调用函数中的ap
值是不确定的,并且应该在进一步引用ap
之前传递给va_end
宏。
Don't pass va_list
objects by value . 不要按值传递va_list
对象。 If your intent is to continue argument parsing in each consequent sub-function, then you have to pass the va_list
object by pointer . 如果您的目的是在每个后续子函数中继续进行参数解析,那么您必须通过指针传递va_list
对象。
If you really want to pass your va_list
object by value , ie if you want each sub-function to parse from the same point, you have to manually copy your va_list
object in advance by using the va_copy
macro. 如果您确实希望按值传递va_list
对象,即如果希望每个子函数从同一点解析,则必须使用va_copy
宏手动复制va_list
对象。 ("In advance" means that you have to make as many copies as you'll need before any sub-function has a chance to do a va_arg
on it.) (“提前”意味着在任何子功能有机会对其执行va_arg
之前,您必须制作所需数量的副本。)
You're passing your va_list
by value. 您按值传递了va_list
。 Try passing a pointer to the one value instead (or if you wanted a C++ only version, you could use a reference): 尝试将指针传递给一个值(或者如果您只想要一个C ++版本,则可以使用引用):
void vProcessList(LPTSTR str, va_list args)
{
vProcessType(&args, 1);
vProcessType(&args, 2);
vProcessType(&args, 1);
}
void vProcessType(va_list *args, int type)
{
...
LPTSTR str = va_arg(*args, LPTSTR);
...
int num = va_arg(*args, int);
}
As others have noted, the C99 standard allows a portable (among C99 implementations) way for a program to run through a va_list more than once. 正如其他人所指出的那样,C99标准允许程序通过va_list多次运行便携式(在C99实现中)方式。 There isn't any nice portable way to do that in pre-C99 implementations. 在C99之前的实现中没有任何好的可移植方法。 What I did when I needed to run through a printf list more than once (for a "center string" function which had to evaluate the arguments once to determine how wide they would be, and then a second time to actually display them) was to examine the compiler vendor's "stdarg.h" and fudge my own implementation of the necessary functionality. 当我需要多次运行printf列表时,我做了什么(对于“中心字符串”函数,必须先评估参数一次以确定它们的宽度,然后第二次实际显示它们)检查编译器供应商的“stdarg.h”并捏造我自己实现的必要功能。
If one wanted a really portable implementation that would work on earlier C compilers, and if one knew in advance the maximum number of passes that would be required, I think one could create an array of va_ptr objects, use va_start on all of them, and then pass the array to the child routine. 如果想要一个可以在早期C编译器上运行的真正可移植的实现,并且如果事先知道所需的最大传递次数,我认为可以创建一个va_ptr对象的数组,在所有这些对象上使用va_start,以及然后将数组传递给子例程。 Sorta icky, though. 但是,排序icky。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.