c - `va_num` 在这个可变参数宏中意味着什么?

标签 c gcc visual-c++ c99

似乎不同的编译器处理带有可变参数的宏略有不同。

对于 C99 兼容的编译器,一个特殊的标识符 __VA_ARGS__ 用于表示可变参数列表:

#define MACRO_1(param1, ...) func(param1, __VA_ARGS__)

对于 GNU C 编译器,可以给可变参数列表一个名称:

#define MACRO_2(param1, args...) func(param1, args) // "args..." is the name

但我在 ACPICA 代码中看到以下定义:

#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__)

调用这样的宏是这样的:

uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL);

这似乎是 C99 的方法,但是 va_num 似乎没有用。为什么定义?

ADD 1 - 宏的完整定义

#ifdef USE_EFI_FUNCTION_WRAPPER
#define __VA_NARG__(...)                        \
  __VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N())
#define __VA_NARG_(...)                         \
  __VA_ARG_N(__VA_ARGS__)
#define __VA_ARG_N(                             \
  _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
#define __RSEQ_N()                              \
  10, 9,  8,  7,  6,  5,  4,  3,  2,  1,  0

#define __VA_ARG_NSUFFIX__(prefix,...)                  \
  __VA_ARG_NSUFFIX_N(prefix, __VA_NARG__(__VA_ARGS__))
#define __VA_ARG_NSUFFIX_N(prefix,nargs)        \
  __VA_ARG_NSUFFIX_N_(prefix, nargs)
#define __VA_ARG_NSUFFIX_N_(prefix,nargs)       \
  prefix ## nargs

/* Prototypes of EFI cdecl -> stdcall trampolines */

UINT64 efi_call0(void *func);
UINT64 efi_call1(void *func, UINT64 arg1);
UINT64 efi_call2(void *func, UINT64 arg1, UINT64 arg2);
UINT64 efi_call3(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3);
UINT64 efi_call4(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4);
UINT64 efi_call5(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4, UINT64 arg5);
UINT64 efi_call6(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4, UINT64 arg5, UINT64 arg6);
UINT64 efi_call7(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7);
UINT64 efi_call8(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
                 UINT64 arg8);
UINT64 efi_call9(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                 UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
                 UINT64 arg8, UINT64 arg9);
UINT64 efi_call10(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
                  UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
                  UINT64 arg8, UINT64 arg9, UINT64 arg10);

/* Front-ends to efi_callX to avoid compiler warnings */

#define _cast64_efi_call0(f) \
  efi_call0(f)
#define _cast64_efi_call1(f,a1) \
  efi_call1(f, (UINT64)(a1))
#define _cast64_efi_call2(f,a1,a2) \
  efi_call2(f, (UINT64)(a1), (UINT64)(a2))
#define _cast64_efi_call3(f,a1,a2,a3) \
  efi_call3(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3))
#define _cast64_efi_call4(f,a1,a2,a3,a4) \
  efi_call4(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4))
#define _cast64_efi_call5(f,a1,a2,a3,a4,a5) \
  efi_call5(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
            (UINT64)(a5))
#define _cast64_efi_call6(f,a1,a2,a3,a4,a5,a6) \
  efi_call6(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
            (UINT64)(a5), (UINT64)(a6))
#define _cast64_efi_call7(f,a1,a2,a3,a4,a5,a6,a7) \
  efi_call7(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
            (UINT64)(a5), (UINT64)(a6), (UINT64)(a7))
#define _cast64_efi_call8(f,a1,a2,a3,a4,a5,a6,a7,a8) \
  efi_call8(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
            (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8))
#define _cast64_efi_call9(f,a1,a2,a3,a4,a5,a6,a7,a8,a9) \
  efi_call9(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
            (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \
            (UINT64)(a9))
#define _cast64_efi_call10(f,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) \
  efi_call10(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
             (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \
             (UINT64)(a9), (UINT64)(a10))

/* main wrapper (va_num ignored) */

#define uefi_call_wrapper(func,va_num,...)                        \
  __VA_ARG_NSUFFIX__(_cast64_efi_call, __VA_ARGS__) (func , ##__VA_ARGS__)

#else

#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__)

#endif

最佳答案

va_num 只是传递给函数的普通参数,宏会忽略它。

用法一:

当跨不同的编译器设置使用宏时,这种用法很常见,以便在所有这些设置中调用相同的函数,但映射到不同的 func,这可能(或可能不) 支持 va_num 参数。在这种特殊情况下,func 可能不支持 va_num 参数,因此宏会忽略它。

用法 2:

也可用于处理旧代码,使其易于移植到新版本的宏。

回答您的问题,va_num 参数不是特殊参数。它与任何其他参数一样使用,与 __VA_ARGS__ 或类似参数无关。宏的编写者决定给那个参数起那个名字,只是为了说明它应该包含传递的参数的数量,但没有什么更花哨的,也没有编译器注意到。

关于c - `va_num` 在这个可变参数宏中意味着什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44754209/

相关文章:

c - 信号系统调用

c - PostgreSQL 中的聚合函数将数组传递给 C 函数

linux - 如何重新映射符号以调用不同的函数

windows - 从 Vista 上的服务使用 CreateProcessAsUser 的桌面问题

qt - 无法构建 C++ 项目

c++ - Visual C++ 做深拷贝的好方法?

c - 在c中使用do while循环来表示yes no提示

c - 无法复制堆栈缓冲区溢出漏洞利用

c++ - MacPorts: “Error: clang-4.0 has been replaced by clang-8.0; please install that instead”,但我已经安装了clang-8.0

c++ - 从源代码构建 GCC 5.4;如此构建的可执行文件尝试链接不兼容的 libstdc++ 并且无法运行