【问题标题】:Passing pointer to variadic arguments in C++?在 C++ 中传递指向可变参数的指针?
【发布时间】:2013-04-17 07:35:16
【问题描述】:

我希望通过指针将可变数量的参数传递给也被指针引用的回调函数。有什么方法可以创建一个可以通过引用传递的参数列表?

例如:

typedef struct MENUELEMENT
{
  void* OK_func; void* OK_args;
} menuElement_t;

menuElement_t* curMenuElement;

menuElement_t menu[] =
{
  //First Menu Element
  (void*)menuDisplayText, (void*)("Test", (char*)&lcdBuffer[0]) //menuDisplayText is a function that takes two arguments
  //Second Menu Element
  (void*)menuDisplayVal, (void*)&value[0] //menuDisplayVal is a function that takes one argument
};

void loop() //Main Loop - just an example of how the function pointed to by curMenuElement is executed
{
  curMenuElement = &menu[0];
  if(KP_OK)
  {
    (*reinterpret_cast<void (*)(...)>(curMenuElement->OK_func))(curMenuElement->OK_args); //General template for function pointed to at OK_func with OK_args
  }
}

到目前为止,这适用于一个参数,但是我无法弄清楚如何在 struct 变量的初始化中传递多个参数的列表。这甚至可以在不必使用使用 va_list 的构建器函数的情况下实现吗?

【问题讨论】:

  • 这里没有 C。只是 C++... 和 what is void main()?.. 和 why shouldn't you use it?
  • 将函数指针强制转换为void*是非法的。
  • @JesseGood 确实如此。 lambda 的类型是void * 在哪一天和哪一天?那将是一个极其混乱的时代!
  • @JesseGood:绝对正确,尽管符合 POSIX 的系统要求函数指针和 void* 由于 dlsym() function 而可以互换
  • FWIW - 这是一个嵌入式系统,只是一个例子来说明我想要完成的概念。如果您对文体有任何见解,而不是 cmets,那将不胜感激!

标签: c++ pointers arguments function-pointers


【解决方案1】:

可变参数函数只接受堆栈上的参数。循环必须知道给定函数的结构中有多少参数值,然后下拉到汇编层以手动将值压入堆栈,然后调用当前函数,最后将值弹出函数退出后的栈。这当然是可行的,但手动完成的工作量很大,而且您会安全地失去编译时间。

您最好将结构本身或至少其成员传递给每个函数,并让他们根据需要决定如何使用这些值。例如:

typedef void (*menuFunc)(void** args, int numArgs);

typedef struct MENUELEMENT
{
    menuFunc OK_func;
    int OK_num_args;
    void** OK_args;
} menuElement_t;

.

void menuDisplayText(void** args, int numArgs)
{
    ...
}

void menuDisplayVal(void** args, int numArgs)
{
    ...
}

void* menuDisplayTextArgs[] =
{
    "Test"
    &lcdBuffer[0]
};

menuElement_t menu[] =
{
  {&menuDisplayText, 2, menuDisplayTextArgs},
  {&menuDisplayVal, 1, &value[0]}
};

.

void loop()
{
    menuElement_t* curMenuElement = &menu[0];
    if (KP_OK)
    {
        curMenuElement->OK_func(curMenuElement->OK_args, curMenuElement->OK_num_args);
    }
}

【讨论】:

  • “这当然是可行的”它只适用于特定的架构和调用约定。它不会是便携式的
  • 当下拉到组装层时,您必须编写特定于平台的指令。在 32 位平台上,唯一支持可变参数的调用约定是 cdecl,这是一种具有明确定义的堆栈布局的可移植调用约定。在 64 位平台上,只有一种调用约定可用,但它实现可变参数的方式在 AMD 与 Intel、GCC 与 VC++ 等之间有所不同。所以是的,编写低级代码不是很便携……
  • ... 但是,如果您想动态构建函数的参数列表,就像 OP 要求的那样,没有其他方法。因此我的建议是不要尝试它,而是将代码重新编写成语言更好支持的东西,而不诉诸低级技巧,让编译器处理平台问题。
  • 谢谢你 - 从概念上讲它很好,但是我知道面临的问题是对于 menuElement 结构的每个成员,需要定义七个不同的函数和相关参数乘以几个十几个 menuElement 元素。如果我可以在结构本身(为了代码整洁)而不是在数组之外声明这些数据,那将是理想的。不过谢谢你,通过为每个成员声明一个 void*,我可以用我的原始代码传递它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
相关资源
最近更新 更多