簡體   English   中英

va_arg返回錯誤的參數

[英]va_arg returning the wrong argument

使用以下代碼,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的東西? 在vProcessType中第一次調用va_arg會返回預期的字符串。 第二次和第三次通過此函數返回指向第一個字符串開頭的指針,而不是預期的值。

如果我將va_arg調用提升到vProcessList,一切似乎都能正常工作。 只有當我通過函數傳遞va_list時才會出現這種行為。

您每次都將相同的va_list傳遞給vProcessType() - 在每次調用vProcessType()您將對列表中的第一個va_arg執行操作。

因此,在調用vProcessType()時,您始終處理TEXT("foobar")參數。

另請注意,標准有關於將va_list傳遞給另一個函數的說法:

對象ap [類型為va_list ]可以作為參數傳遞給另一個函數; 如果該函數使用參數ap調用va_arg宏,則調用函數中的ap值是不確定的,並且應該在進一步引用ap之前傳遞給va_end宏。

標准中的腳注表明將指針傳遞給va_list是完美的,所以你可能要做的是讓vProcessType()獲取指向va_list的指針:

void vProcessType(va_list* pargs, int type);

當您將va_list對象傳遞給另一個函數並且另一個函數在相應參數上使用va_arg時,該控件返回時該va_list將在調用函數中具有不確定的值 您唯一可以做的是將va_end應用於該va_list對象。

這就是標准中規定的方式(7.15 / 3)

如果需要訪問變量參數,則被調用函數應聲明類型為va_list的對象(在va_list條款中通常稱為ap )。 對象ap可以作為參數傳遞給另一個函數; 如果該函數使用參數ap調用va_arg宏,則調用函數中的ap值是不確定的,並且應該在進一步引用ap之前傳遞給va_end宏。

不要按值傳遞va_list對象。 如果您的目的是在每個后​​續子函數中繼續進行參數解析,那么您必須通過指針傳遞va_list對象。

如果您確實希望按值傳遞va_list對象,即如果希望每個子函數從同一點解析,則必須使用va_copy宏手動復制va_list對象。 (“提前”意味着在任何子功能有機會對其執行va_arg之前,您必須制作所需數量的副本。)

您按值傳遞了va_list 嘗試將指針傳遞給一個值(或者如果您只想要一個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);
}

正如其他人所指出的那樣,C99標准允許程序通過va_list多次運行便攜式(在C99實現中)方式。 在C99之前的實現中沒有任何好的可移植方法。 當我需要多次運行printf列表時,我做了什么(對於“中心字符串”函數,必須先評估參數一次以確定它們的寬度,然后第二次實際顯示它們)檢查編譯器供應商的“stdarg.h”並捏造我自己實現的必要功能。

如果想要一個可以在早期C編譯器上運行的真正可移植的實現,並且如果事先知道所需的最大傳遞次數,我認為可以創建一個va_ptr對象的數組,在所有這些對象上使用va_start,以及然后將數組傳遞給子例程。 但是,排序icky。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM