Step to UEFI (234)不定参数函数的测试

一些情况下,调用函数的参数并不确定,显而易见的一个例子是 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()能够实现在屏幕输出可变个字符串变量的功能。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注