Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

va_arg returning the wrong argument

With the following code va_arg is returning garbage for the second and third pass through 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? The first call to va_arg inside vProcessType returns the expected string. 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. It only seems when I pass a va_list through a function that I'm getting this behaviour.

like image 842
Jonathan Yee Avatar asked Apr 26 '26 04:04

Jonathan Yee


1 Answers

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.

So you're always dealing with the TEXT("foobar") parameter when calling vProcessType().

Also note that the standard has this to say about passing a va_list to another function:

The object ap [of type va_list] may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.

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:

void vProcessType(va_list* pargs, int type);
like image 66
Michael Burr Avatar answered Apr 28 '26 18:04

Michael Burr