一些情况下,调用函数的参数并不确定,显而易见的一个例子是 printf,在调用的时候后面可能接多个参数,对于这种情况我们可以使用 VA_LIST 来解决。在 Base.h 中有定义:
//
// Support for variable argument lists in freestanding edk2 modules.
//
// For modules that use the ISO C library interfaces for variable
// argument lists, refer to "StdLib/Include/stdarg.h".
//
// VA_LIST - typedef for argument list.
// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use.
// VA_END (VA_LIST Marker) - Clear Marker
// VA_ARG (VA_LIST Marker, var arg type) - Use Marker to get an argument from
// the ... list. You must know the type and pass it in this macro. Type
// must be compatible with the type of the actual next argument (as promoted
// according to the default argument promotions.)
// VA_COPY (VA_LIST Dest, VA_LIST Start) - Initialize Dest as a copy of Start.
//
// Example:
//
// UINTN
// EFIAPI
// ExampleVarArg (
// IN UINTN NumberOfArgs,
// ...
// )
// {
// VA_LIST Marker;
// UINTN Index;
// UINTN Result;
//
// //
// // Initialize the Marker
// //
// VA_START (Marker, NumberOfArgs);
// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
// //
// // The ... list is a series of UINTN values, so sum them up.
// //
// Result += VA_ARG (Marker, UINTN);
// }
//
// VA_END (Marker);
// return Result;
// }
//
// Notes:
// - Functions that call VA_START() / VA_END() must have a variable
// argument list and must be declared EFIAPI.
// - Functions that call VA_COPY() / VA_END() must be declared EFIAPI.
// - Functions that only use VA_LIST and VA_ARG() need not be EFIAPI.
//
根据上面的代码,编写测试例子如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
UINTN
EFIAPI
VarSum (
IN UINTN NumberOfArgs,
...
)
{
VA_LIST Marker;
UINTN Index;
UINTN Result;
//
// Initialize the Marker
//
VA_START (Marker, NumberOfArgs);
for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
//
// The ... list is a series of UINTN values, so sum them up.
//
Result += VA_ARG (Marker, UINTN);
}
VA_END (Marker);
return Result;
}
UINTN
EFIAPI
VarString (
IN UINTN NumberOfArgs,
...
)
{
VA_LIST Marker;
UINTN Index;
UINTN Result;
//
// Initialize the Marker
//
VA_START (Marker, NumberOfArgs);
for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
//
// The ... list is a series of UINTN values, so sum them up.
//
//Result += VA_ARG (Marker, UINTN);
Print(L"String %d: %s\n",Index,VA_ARG (Marker, CHAR16*));
}
VA_END (Marker);
return Result;
}
/***
Print a welcoming message.
Establishes the main structure of the application.
@retval 0 The application exited normally.
@retval Other An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
Print(L"VarSum(2,1,2)=%d\n",VarSum(2,1,2));
Print(L"VarSum(3,1,2,3)=%d\n",VarSum(3,1,2,3));
Print(L"VarSum(4,1,2,3,4)=%d\n",VarSum(4,1,2,3,4));
Print(L"VarString(4,L\"abcde\",L\"1234\",L\"efgh\",L\"5678\")\n",
VarString(4,L"abcde",L"1234",L"efgh",L"5678"));
return(0);
}
运行结果:
可以看到VarSum()能够实现将可变个数值相加,VarString()能够实现在屏幕输出可变个字符串变量的功能。