c++ - 函数参数中的省略号是否使用与普通参数相同的调用布局

标签 c++ language-lawyer variadic-functions

我想调用一个 extern "C" 函数,例如f1(int a, float f, double d, void* ptr) 使用带有实际参数的前向声明,但在实际实现中我想使用 va_list 和 friend pop 参数。让我们想象一下,我有一个有效的用例,它被允许吗?

main.cpp

extern "C" void f(int anchor, int a, float f, double d, void* ptr, char c);

int main(int, char*)
{
   f(0, 42, 1.08f, 3.14, reinterpret_cast<void*>(0xcafebabe), 'c');
   return 0;
}

impl.cpp

#include <cstdarg>
#include <iostream>
#include <iomanip>

using namespace std;

void f(int anchor, ...)
{
  va_list args;
  va_start(args, anchor);

  int a = va_arg(args, int);
  float f = va_arg(args, float);
  double d = va_arg(args, double);
  void* ptr = va_arg(args, void*);
  char c = va_arg(args, char);

  cout << a << ' '
       << f << ' '
       << d << ' '
       << hex << (std::ptrdiff_t)ptr << ' '
       << (int)c << endl;

  va_end(args);
}

代码至少在 MSVC 2015 上运行并打印正确的值,现在的问题是:它是否保证可以工作,如果不能:它是否可能在最重要的平台和编译器上工作?

最佳答案

从理论上讲,您的代码会受到未定义行为的影响。事实上,当我尝试在使用 g++ 构建后运行该程序时,我得到了

Illegal instruction (core dumped)

原因是当一个函数有可变参数时,它能处理的只有intdouble、指针。它无法处理 floatchar

如果声明被指定为:

extern "C" void f(int anchor, ...);

float 将被提升为 doublechar 将被提升为 int

在实现方面,您需要使用:

 float f = (float)va_arg(args, double);

 char c = (char)va_arg(args, int);

参见 Default argument promotions in C function calls有关该主题的更多信息。

关于c++ - 函数参数中的省略号是否使用与普通参数相同的调用布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33696478/

相关文章:

java - java中的string args[]是作为varargs实现的吗?

c - __cdecl 参数 "..."和 __VA_ARGS__

c++ - 如何使用 Code::Blocks 或 MinGW 在 Windows 上构建 CPP-NETLIB 库

c++ - 代码中哪里定义了DEBUG?

c++ - 模板模板参数和转发引用

C: 使用 stdarg.h 的可变参数列表

c++ - 来自具有 std::unordered_multimap 等效键的元素的随机元素

c++ - CreateThread 传递 std::string 作为参数

c - 为什么函数调用不是左值

c++ - C++ 标准在哪里允许指向未定义类型的指针?