Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 返回错误参数的va_arg_C++_C_Variadic Functions - Fatal编程技术网

C++ 返回错误参数的va_arg

C++ 返回错误参数的va_arg,c++,c,variadic-functions,C++,C,Variadic Functions,使用以下代码,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, ...)

使用以下代码,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;
    }
}
//va_list_test.cpp:定义控制台应用程序的入口点。
//
#包括“stdafx.h”
#包括
#包括
#包括
无效进程列表(LPTSTR str,…);
void vProcessList(LPTSTR str、va_list args);
void vProcessType(va_列表参数,int类型);
int _tmain(int argc,_TCHAR*argv[]
{
LPTSTR a=文本(“foobar”);
int b=1234;
LPTSTR c=文本(“你好世界”);
流程列表(文本(“foobar”)、a、b、c;
返回0;
}
无效进程列表(LPTSTR str,…)
{
va_列表参数;
va_开始(args、str);
vProcessList(str,args);
va_端(args);
}
void vProcessList(LPTSTR str、va_列表参数)
{
vProcessType(args,1);
vProcessType(args,2);
vProcessType(args,1);
}
void vProcessType(va_列表参数,int类型)
{
开关(类型)
{
案例1:
{
LPTSTR str=va_arg(args,LPTSTR);
printf(“%s”,str);
}
打破
案例2:
{
int num=va_arg(args,int);
printf(“%d”,num);
}
打破
违约:
打破
}
}
以这种方式传递va_列表是不允许的吗?vProcessType内对va_arg的第一次调用返回预期的字符串。第二次和第三次通过此函数返回指向第一个字符串开头的指针,而不是预期的值


如果我将va_arg调用提升到vProcessList,一切似乎都正常。似乎只有当我通过一个函数传递一个va_列表时,我才得到这种行为。

您每次都将相同的
va_列表
传递给
vProcessType()
——在对
vProcessType()
的每次调用中,您都在处理列表中的第一个
va_arg

因此,在调用
vProcessType()
时,您总是要处理
TEXT(“foobar”)
参数

还要注意的是,该标准规定将
va_列表
传递给另一个函数:

对象
ap
[类型
va_list
]可以作为参数传递给另一个函数;如果该函数使用参数
ap
调用
va_arg
宏,则调用函数中
ap
的值是不确定的,应在进一步引用
ap
之前传递给
va_end

标准中的一个脚注表明,将指针传递到
va_列表
是完全可以的,因此您可能需要做的是让
vProcessType()
获取指向
va_列表
的指针:

void vProcessType(va_list* pargs, int type);

您正在按值传递
va_列表。尝试传递一个指针到一个值(或者如果你想要一个C++版本,你可以使用一个引用):


当您将
va_list
对象传递给另一个函数,并且另一个函数对相应的参数使用
va_arg
时,
va_list
将在控件返回时在调用函数中具有不确定的值。唯一允许您执行的操作是将
va_end
应用于该
va_列表
对象

这就是标准(7.15/3)中的说明

如果无法访问不同的参数 如果需要,被调用函数应 声明一个对象(通常指 作为本子条款中的
ap
),具有 键入
va_列表
。对象
ap
可能是 作为论据传递给另一方 功能;如果该函数调用
va_arg
带有参数
ap
的宏 调用函数中
ap
的值为 不确定,并应传递给 在执行任何进一步操作之前,先执行
va_end
宏 参考
ap

不要按值传递对象。如果您的目的是在每个后续子函数中继续参数解析,那么您必须通过指针传递
va_列表
对象


如果确实希望通过值传递
va_列表
对象,即如果希望从同一点解析每个子函数,则必须使用
va_copy
宏提前手动复制
va_列表
对象。(“提前”意味着在任何子函数有机会在其上执行
va_arg
之前,您必须制作所需的尽可能多的副本。)

正如其他人所指出的,C99标准允许程序以可移植的方式(在C99实现中)在va_列表中运行多次。在C99之前的实现中,没有任何好的可移植方式可以做到这一点。当我需要不止一次地运行printf列表时(对于一个“中心字符串”函数,它必须计算一次参数以确定它们的宽度,然后第二次实际显示它们),我所做的是检查编译器供应商的“stdarg.h”,并伪造我自己实现的必要功能


如果想要一个能在早期C编译器上运行的真正可移植的实现,并且事先知道所需的最大传递次数,我认为可以创建一个va_ptr对象数组,在所有对象上使用va_start,然后将该数组传递给子例程。不过有点恶心。

。。。这是未定义的行为。如果
va_list
对象是
va_copy
宏,则制作副本的唯一合法方法是。也就是说,如果说“您正在执行列表中的第一个
va_arg
”,则不完全正确。行为只是没有定义。/facepalm谢谢,我将vProcessType改为vProcessType(va_list*pArgs,int-type),并在vProcessType的末尾添加了一个“*pArgs=args”。似乎已经奏效了。谢谢您的帮助。@AudreyT Windows似乎没有va_copy宏。这里推荐的解决方案是什么?@Jonathan Yee:这取决于你的意图(阅读我的答案)。简而言之:如果您想要连续解析,您必须通过
va\l
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);
}