使用函数指针将 C 转换为 CPP

Converting C to CPP with Function Pointers

本文关键字:转换 CPP 函数 指针      更新时间:2023-10-16

在我的C代码中,我有以下几行:

void* (*functionSteps[numSteps])();
functionSteps[0] = (void*) filterEvenFoos;
functionSteps[1] = (void*) timesFooByTwo,
functionSteps[2] = (void*) mapFooToBar;

哪个工作正常。我有一个函数数组,它们返回一个 void* 类型并接受任意数量的输入。

我试图在C++中做同样的事情,但出现错误

assigning to 'void *(*)()' from incompatible type 'void *'

这在CPP中是不可能的吗?

这在 CPP 中是不可能的吗?

functionSteps[0] = (void*) filterEvenFoos;

不,不是。

它也不是真正有效的 C。

关于函数到指针的转换

从 https://en.cppreference.com/w/c/language/conversion#Function_to_pointer_conversion:

任何函数指示符表达式,当用于除

  • 作为地址运算符的操作数
  • 作为大小的操作数

转换为指向表达式指定的函数的非左值指针。

它没有说明将void*转换为函数指针的任何内容。

关于从void*转换

您可以将void*转换为对象指针。

从 https://en.cppreference.com/w/c/language/conversion#Pointer_conversions:

指向

void 的指针可以隐式转换为指向对象类型的任何指针,这些指针具有以下语义:

  • 如果将指向对象的指针转换为指向 void 的指针并返回,则其值与原始指针相等。
  • 不提供其他保证

请注意,即使在该部分中,也没有提到将void*转换为函数指针。

我不清楚为什么您的计算机不将其报告为错误。

您可以使用

functionSteps[0] = filterEvenFoos;

如果filterEvenFoos功能类型正确。如果filterEvenFoos的声明与预期类型不完全匹配,即不带参数并返回void*的函数,那么您也不能使用它。

这在 CPP 中是不可能的吗?

严格来说,没有,由于类型安全和其他管理功能原型的规则。但是,根据您的需要,可以将该 C 代码移植到 C++。

首先,需要注意的是,void* fn();在C语言中的函数签名在C++中并不相同。C++要获得相同的函数签名,您需要引入如下可变参数:void* fn(...);,但是,应该注意的是,对于这样的函数签名,您无法可移植地访问可变参数。

在C++中,void* fn();与 C 中的void* fn(void);相同。为此,如果您的函数在 C 中具有变量输入,则需要在使用可变参数列表进行一些额外的C++工作。

例如,如果您的代码类似于以下 C 代码:

#include <stdio.h>
#define NUM_STEPS 3
static void* filterEvenFoos(void)
{
printf("42n");
return NULL;
}
static void* timesFooByTwo(int val)
{
printf("%dn", (val * 2));
return NULL;
}
static void* mapFooToBar(double obj1, size_t obj2)
{
printf("foo(%f)->bar(%zu)n", obj1, obj2);
return NULL;
}
int main(void) 
{
void* (*functionSteps[NUM_STEPS])();
functionSteps[0] = (void*)filterEvenFoos;
functionSteps[1] = (void*)timesFooByTwo;
functionSteps[2] = (void*)mapFooToBar;
functionSteps[0]();
functionSteps[1](42);
functionSteps[2](3.14, &main);
return 0;
}

您可以通过多种方式将其移植到 C++,但您可以使用va_arg功能来获取变量输入,如下所示:

#include <iostream>
#include <cstdarg>
#include <vector>
static void* filterEvenFoos(int na, ...)
{
std::cout << 42 << std::endl;
return NULL;
}
static void* timesFooByTwo(int na, ...)
{
va_list vl;
va_start(vl, na);
std::cout << ((va_arg(vl, int)) * 2) << std::endl;
va_end(vl);
return NULL;
}
static void* mapFooToBar(int na, ...)
{
va_list vl;
va_start(vl, na);
double obj1 = va_arg(vl, double);
size_t obj2 = va_arg(vl, size_t);
std::cout << "foo(" << obj1 << ")->bar(" << obj2 << ")" << std::endl;
va_end(vl);
return NULL;
}
int main(int argc, char* argv[])
{
std::vector<void* (*)(int, ...)> functionSteps;
functionSteps.push_back(&filterEvenFoos);
functionSteps.push_back(&timesFooByTwo);
functionSteps.push_back(&mapFooToBar);
functionSteps[0](0);
functionSteps[1](0, 42);
functionSteps[2](0, 3.14, &main);
return 0;
}

您可能会注意到,函数签名略有变化,以允许以可移植的方式访问每个函数中的可变参数。

如果您使用的是 C++11,您也可以使用vector内部的std::function,但您仍然需要具有匹配的函数签名。

您还可以使用类和继承或模板专用化,但在您的方案中,这些可能是极端的矫枉过正。

最后,它不是从 C 代码到 C++ 的直接端口,但它是可行的。

希望能有所帮助。

这是可能的,但语法有点难以正确。 如果你对回调函数类型使用 typedef 会更容易,如下所示:

#include <stdio.h>
void* filterEvenFoos() {return NULL;}
void* timesFooByTwo() {return NULL;}
void* mapFooToBar() {return NULL;}
typedef void* (*VoidFunction)();
int main(int, char **)
{
const int numSteps = 3;
VoidFunction functionSteps[numSteps];
functionSteps[0] = filterEvenFoos;
functionSteps[1] = timesFooByTwo;
functionSteps[2] = mapFooToBar;
}