一. 遍历可变参数
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);
}
{
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);
}
调用方法:“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 ;
}
{
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 < 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 < j ; i ++ )
{
stmt.bind(i,va_arg(ap, char * ));
}
stmt.execDML();
}
catch (CppSQLite3Exception e)
{
bResult = FALSE;
}
catch (...)
{
bResult = FALSE;
}
va_end(ap);
return bResult;
}
{
int iCount = 0 ;
for ( int i = 0 ;i < 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 < j ; i ++ )
{
stmt.bind(i,va_arg(ap, char * ));
}
stmt.execDML();
}
catch (CppSQLite3Exception e)
{
bResult = FALSE;
}
catch (...)
{
bResult = FALSE;
}
va_end(ap);
return bResult;
}
代码说明:
这段代码是在使用Sqlite时封装的一段代码,尽量保持了C#的命名比较习惯一点,这段代码只是编译通过了,这里仅用于说明这个道理和用法,是不是和Format很像 :)
i. 使用:ExecuteNonQuery("update test set c1 = ? where id = ? ","abc","1")
本文转自博客园农民伯伯的博客,原文链接:[C++]遍历可变参数 (va_list),如需转载请自行联系原博主。