天天看点

[C++]遍历可变参数 (va_list)

一.  遍历可变参数

    1.1  传入的时候指定参数个数

void arg_cnt(int cnt, ...)

{

    int value=0;

    int i=0;

    int arg_cnt=cnt;

    va_list arg_ptr; 

    va_start(arg_ptr, cnt); 

    for(i = 0; i < cnt; i++)

    {

        value = va_arg(arg_ptr,int);

        printf("value%d=%d\n", i+1, value);

    }

    va_end(arg_ptr);

<a></a>

      调用方法:“arg_cnt(4,1,2,3,4);”,第一个参数为传入参数个数。

    1.2  传入的时候指定特殊的字符以标示为结

int demo( char msg, ... )

    va_list argp;

    int argno = 0;

    char para;

    va_start( argp, msg );

    while (1)

        para = va_arg( argp, char);

        if ( strcmp( para, "") == 0 )

            break;

        printf("Parameter #%d is: %s\n", argno, para);

        argno++;

    va_end( argp );

    return 0;

      调用方法:“demo("DEMO", "This", "is", "a", "demo!", "");”,最后一个参数标示结束。

二.  探讨CString的Format方法

    在学可变参数这节的时候一直很向往能达到这种效果,即不用多传一个参数来指定结束。我臆断有两种情况来实现:

    a).  编译器做了手脚

      编译之后有可能改变了函数多传入了一个参数的个数,有几个参数编译的时候是能够知道的。

    b).  使用"%"作为特殊符号

      实践中发现如果有%字符出现在Format中的话是会报错的,所有我推断他统计了"%"出现的次数,然后解析"%"后面的参数,比如"%d"、"%s",通过统计"%"出现的次数就能够解决参数个数的难度,也就不用我们传入参数个数来实现遍历了。

    c).  类似实现代码

int FindCharCount(CString csStr,char c)

    int iCount = 0;

    for(int i=0;i&lt;csStr.GetLength();i++)

       i = csStr.Find(c ,i + 1 );

       iCount++;

    return iCount;

}

BOOL CppSQLite3Helper::ExecuteNonQuery(char * commandText,const char *params...)

    BOOL bResult = TRUE;

    va_list ap;

    try

        va_start(ap,params);

        CppSQLite3Statement stmt = m_db.compileStatement(commandText);

        for(int i = 0 , j = FindCharCount(CString(commandText),'?')  ; i &lt; j ; i ++)

        {

            stmt.bind(i,va_arg(ap,char *));

        }

        stmt.execDML();

    catch(CppSQLite3Exception e)

        bResult = FALSE;

    catch(...)

    va_end(ap);

    return bResult;

      代码说明:

        这段代码是在使用Sqlite时封装的一段代码,尽量保持了C#的命名比较习惯一点,这段代码只是编译通过了,这里仅用于说明这个道理和用法,是不是和Format很像 :)

        i.  使用:ExecuteNonQuery("update test set c1 = ? where id = ? ","abc","1")