我们在用C语言实现一些功能时,例如:日志分级输出、字符串格式化写入CSV文件等,经常需要用到多个参数,且每次是不固定的参数个数,这就用到了头文件stdarg.h中的相关函数。
参考的是如下版本的相关头文件。
/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/stdarg.h
typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;
va_list定义的是一个参数列表。
__builtin_va_list 没有写具体类型。
头文件中的定义:
#define va_start(v,l) __builtin_va_start(v,l)
初始化可变参数列表va_list类型的v。l为最后一个固定参数的名称。
__builtin_va_start(v,l)没有具体实现。
例如函数声明为:
Status WriteData2Csv(FILE** FilePtr, char* StrFormat, ...)
这里的StrFormat就是l最后一个固定参数的名称。
man查看va_start定义:
void va_start(va_list ap, last);
va_start()宏初始化ap,以供va_arg()和va_end()后续使用,并且必须首先调用。
最后一个参数是变量参数列表之前的最后一个参数的名称,即调用函数的最后一个参数知道类型。
由于此参数的地址可以在 va_start() 宏中使用,因此不应将其声明为寄存器变量、函数或数组类型。
int vsprintf(char *str, const char *format, va_list ap);
函数 vprintf(), vfprintf(), vsprintf(), vsnprintf() 分别等同于函数 printf(), fprintf(), sprintf(), snprintf(), 不同之处在于它们是用 va_list 而不是可变数量的参数调用的。 这些函数不调用va_end宏。
就是将ap(多个参数)按照format(例如:"%s%d%ld")格式化拼成字符串放入str中。
void va_end(va_list ap);
va_start()的每次调用都必须与同一函数中相应的 va_end()调用相匹配。va_end()可以是宏或
函数。
Status WriteData2Csv(FILE** FilePtr, char* StrFormat, ...)
{
JudgeAllNullPointer(*FilePtr);
JudgeAllNullPointer(StrFormat);
char WriteStr[WRITE_CSV_STR_LEN] = {0};
va_list ParameterList; //定义参数列表
va_start(ParameterList, StrFormat); // 初始化可变参数列表ParameterList。StrFormat为最后一个固定参数的名称。
vsprintf(WriteStr, StrFormat, ParameterList); // vsprintf使用参数列表ParameterList发送格式化StrFormat输出到字符串WriteStr。
va_end(ParameterList); // 结束可变参数列表的访问,该宏va_end将ParameterList置为 NULL。
//Log(WriteStr,Debug);
fputs(WriteStr, *FilePtr);
return SuccessFlag;
}
函数实现功能:将数据写入到CSV文件中。
WriteData2Csv(FilePtr,"%s,%s,%s,%s,%d,%s,%d,%s,%d,%d,%d,%s,%s,%s,%s,%d,%s,%d,%s,%d,%s,%s,%s,%s,%s,%s\n",
MBJ->TaskName,
MBJ->ProcessName,
MBJ->JobName,
MBJ->JobDesc,
MBJ->PhysicalJobsType,
MBJ->PhysicalJobsName,
MBJ->DomainNodeType,
MBJ->DomainNodeName,
MBJ->ScheduleJobPriority,
MBJ->JobResourcesNum,
MBJ->MaxParallelDegree,
MBJ->ExecuteCalendar,
MBJ->TimeStartCondition,
MBJ->EstimatedRunTime,
MBJ->EstimatedEndTime,
MBJ->NodeDeathTransferFlag,
MBJ->ReturnDefaultClassName,
MBJ->RecordLog,
MBJ->IndependentResourceName,
MBJ->BreakPointFlag,
MBJ->PreProcessingScripts,
MBJ->PostProcessingScripts,
MBJ->JobParameters,
MBJ->ProcessDependencies,
MBJ->GenerateEvent,
MBJ->DependentEvent);