在函数调用中使用可变数量的参数并将它们委托给另一个函数

时间:2017-02-06 15:19:31

标签: c variadic-functions

我有一个具有以下签名的全局函数:

void Systemfehlerprotokollieren(BYTE quelle,WORD fehlercode,WORD subfehlercode,
    BYTE klassifizierung, BYTE status,BYTE kanalnummer,DWORD detailfehler,
    WORD modulnummer,WORD location,WORD wLenZusatzText,char *pcZusatztext);

这个功能我想以两种方式简化。

  1. 使用printf中的变量参数而不是pcZusatztext
  2. 从而摆脱参数wLenZusatzText
  3. 在本地环境中使用原始签名
  4. 所以我的外部函数(最后的参数)看起来像是:

    ext_Systemfehlerprotokollieren(WORD location, char *form, ...);

    此函数应该像以前一样使用上面提到的参数调用void Systemfehlerprotokollieren(. . . )

    现在我有以下代码部分:

    void vSystemfehlerprotokollierenText(BYTE quelle,WORD fehlercode,WORD subfehlercode,
        BYTE klassifizierung,BYTE status,BYTE kanalnummer,DWORD detailfehler,
        WORD modulnummer,WORD location,va_list args)
    {
        int ret;
        char zepuf_printf_mode_lokal[ZELE];
        memset(&zepuf_printf_mode_lokal[0],0x00,ZELE);
        ret = vsnprintf_s(zepuf_printf_mode_lokal, ZELE-1,_TRUNCATE, "%s",args );
        if (ret != -1)
        {
            if (ret < 0)
            { 
                Systemfehlerprotokollieren(quelle,fehlercode,subfehlercode,
                   klassifizierung,status,kanalnummer,detailfehler,
                   modulnummer,location,0,NULL);
                return;
            }
        }
        Systemfehlerprotokollieren(quelle,fehlercode,subfehlercode,
            klassifizierung,status,kanalnummer,detailfehler,
            modulnummer,location,strlen(zepuf_printf_mode_lokal),zepuf_printf_mode_lokal);
    }
    
    上面的函数Systemfehlerprotokollieren中的

    将照常调用

    void SystemFehlerKG(WORD wFehlerCode, WORD wSubFehlerCode,BYTE KanalNummer,
        DWORD detailinfo2, DWORD detailinfo3, WORD programmstelle, char *form, ... )
    {
        va_list args = NULL ;
        if (form != NULL)
        {
            va_start(args, form);
            vSystemfehlerprotokollierenText(SYS_FEHL_QUELLE_FLEXOS,wFehlerCode,wSubFehlerCode, 
                SYS_FEHL_KLASS_FEHLER, SYS_FEHL_STATUS_FEHLER_KOMMT_GEHT, KanalNummer, 
                (WORD)detailinfo2, (WORD)detailinfo3, programmstelle,args);
            va_end(args);
        }
        else 
            vSystemfehlerprotokollierenText(SYS_FEHL_QUELLE_FLEXOS,wFehlerCode,wSubFehlerCode, 
                SYS_FEHL_KLASS_FEHLER, SYS_FEHL_STATUS_FEHLER_KOMMT_GEHT, KanalNummer, 
                (WORD)detailinfo2, (WORD)detailinfo3, programmstelle,"");
    }
    

    当我调用第二个函数时,这个工作正常:

    SystemFehlerKG(5000+TCPIP_SYS_ERROR_FKT_SEND,0,SYS_FEHL_KANAL_ALLG,
        iRet,0,SFPROG_00000,"%s","");
    

    但我不知道要改变什么以获得与

    相同的结果
    SystemFehlerKG(5000+TCPIP_SYS_ERROR_FKT_SEND,0,SYS_FEHL_KANAL_ALLG,
        iRet,0,SFPROG_00000);
    

    ...省略最后两个参数......

    [编辑#1]:

    我知道,printf();也不起作用,它必须至少printf("");

    所以最接近的方法是

    SystemFehlerKG(5000+TCPIP_SYS_ERROR_FKT_SEND,0,SYS_FEHL_KANAL_ALLG,
        iRet,0,SFPROG_00000,"");
    

    [按照@JanKrüger的建议编辑#2]:

    void SystemFehlerKG(WORD wFehlerCode, WORD wSubFehlerCode,
        BYTE KanalNummer, DWORD detailinfo2, DWORD detailinfo3, 
        WORD programmstelle, char *form, ... )
    {
        va_list args = NULL ;
        va_start(args, form);
        vSystemfehlerprotokollierenText(SYS_FEHL_QUELLE_FLEXOS,wFehlerCode,
            wSubFehlerCode, SYS_FEHL_KLASS_FEHLER,
            SYS_FEHL_STATUS_FEHLER_KOMMT_GEHT, KanalNummer, 
            (WORD)detailinfo2, (WORD)detailinfo3, programmstelle,args);
        va_end(args);
    }
    

    我现在没有手头的代码,但我认为,当form不是有效的(格式)字符串(为NULL或“”)时,这会引发异常。

    我将在明天告诉你。

    [编辑#3:]

    我在编辑#2中对代码进行了更改。不工作。 但我发现了错误:

    void vSystemfehlerprotokollierenText(BYTE quelle,WORD fehlercode,WORD subfehlercode, BYTE klassifizierung,BYTE status,BYTE kanalnummer,DWORD detailfehler, WORD modulnummer,WORD location,va_list args)

    需要

    void vSystemfehlerprotokollierenText(BYTE quelle,WORD fehlercode,WORD subfehlercode, BYTE klassifizierung,BYTE status,BYTE kanalnummer,DWORD detailfehler, WORD modulnummer,WORD location,char * form, va_list args)

    还必须更改函数SystemfehlerKG以反映参数form

    有一件事我还不是很清楚: 如果我在我最顶层的函数中使用...并想要调用另一个使用...签名的函数,那么我必须注意什么?

1 个答案:

答案 0 :(得分:1)

您的编辑很容易被发现。在printf和朋友中,格式字符串不是函数签名的可变参数部分。你必须将它作为正常参数单独传递。

另一个重要的一点是:总是必须将va_list结构传递给vsnprintf_s(通过您的vSystemfehlerprotokollieren),即使您已经确定没有额外的论点。因此,请勿使va_startva_end成为条件。