使用函数指针将 C 转换为 CPP
Converting C to CPP with Function Pointers
在我的 C 代码中,我有以下几行:
void* (*functionSteps[numSteps])();
functionSteps[0] = (void*) filterEvenFoos;
functionSteps[1] = (void*) timesFooByTwo,
functionSteps[2] = (void*) mapFooToBar;
效果很好。我有一个函数数组,return 一个 void* 类型并接受任意数量的输入。
我尝试在 C++ 中执行相同的操作,但出现错误
assigning to 'void *(*)()' from incompatible type 'void *'
这在CPP中是不可能的吗?
Is this not possible in CPP?
functionSteps[0] = (void*) filterEvenFoos;
不,不是。
它也不是真正有效的 C。
关于函数到指针的转换
来自 https://en.cppreference.com/w/c/language/conversion#Function_to_pointer_conversion:
Any function designator expression, when used in any context other than
- as the operand of the address-of operator
- as the operand of sizeof
undergoes a conversion to the non-lvalue pointer to the function designated by the expression.
它没有说明将 void*
转换为函数指针。
关于来自 void*
的转化
您可以将 void*
转换为对象指针。
来自 https://en.cppreference.com/w/c/language/conversion#Pointer_conversions:
A pointer to void can be implicitly converted to and from any pointer to object type with the following semantics:
- If a pointer to object is converted to a pointer to void and back, its value compares equal to the original pointer.
- No other guarantees are offered
请注意,即使在那一节中,也没有提及将 void*
转换为函数指针。
我不清楚为什么您的计算机没有将其报告为错误。
您可以使用
functionSteps[0] = filterEvenFoos;
如果filterEvenFoos
是正确的函数类型。如果 filterEvenFoos
的声明与预期类型不完全匹配,即一个不带参数的函数和 returns 一个 void*
,那么你也不能使用它。
这是可能的,但要正确使用语法有点冒险。如果您为回调函数类型使用 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;
}
Is this not possible in CPP?
严格来说,不可以,因为类型安全和其他管理函数原型的规则。但是,根据您的需要,该 C 代码可以移植到 C++。
首先需要注意的是void* fn();
在C中的函数签名在C++中是不一样的。在 C++ 中要获得相同的函数签名,您需要像这样引入 variadic arguments:void* fn(...);
,但是,应该注意的是,对于这样的函数签名,您不能可移植地访问可变参数。
在 C++ 中,void* fn();
与 C 中的 void* fn(void);
相同。为此,如果您的函数在 C 中有变量输入,您需要在 C++ 中使用可变参数列表。
例如,如果您的代码类似于以下 C 代码:
#include <stdio.h>
#define NUM_STEPS 3
static void* filterEvenFoos(void)
{
printf("42\n");
return NULL;
}
static void* timesFooByTwo(int val)
{
printf("%d\n", (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(×FooByTwo);
functionSteps.push_back(&mapFooToBar);
functionSteps[0](0);
functionSteps[1](0, 42);
functionSteps[2](0, 3.14, &main);
return 0;
}
您可能会注意到函数签名略有变化,以允许以可移植的方式访问每个函数中的可变参数。
如果您使用的是 C++11,您也可以使用 std::function
inside the vector
,但您仍然需要具有匹配的函数签名。
您也可以利用 类 和继承,或模板特化,但在您的场景中这些可能是极端的过度杀戮。
最后,它不是从 C 代码到 C++ 的直接端口,但它是可行的。
希望能帮到你。
在我的 C 代码中,我有以下几行:
void* (*functionSteps[numSteps])();
functionSteps[0] = (void*) filterEvenFoos;
functionSteps[1] = (void*) timesFooByTwo,
functionSteps[2] = (void*) mapFooToBar;
效果很好。我有一个函数数组,return 一个 void* 类型并接受任意数量的输入。
我尝试在 C++ 中执行相同的操作,但出现错误
assigning to 'void *(*)()' from incompatible type 'void *'
这在CPP中是不可能的吗?
Is this not possible in CPP?
functionSteps[0] = (void*) filterEvenFoos;
不,不是。
它也不是真正有效的 C。
关于函数到指针的转换
来自 https://en.cppreference.com/w/c/language/conversion#Function_to_pointer_conversion:
Any function designator expression, when used in any context other than
- as the operand of the address-of operator
- as the operand of sizeof
undergoes a conversion to the non-lvalue pointer to the function designated by the expression.
它没有说明将 void*
转换为函数指针。
关于来自 void*
的转化
您可以将 void*
转换为对象指针。
来自 https://en.cppreference.com/w/c/language/conversion#Pointer_conversions:
A pointer to void can be implicitly converted to and from any pointer to object type with the following semantics:
- If a pointer to object is converted to a pointer to void and back, its value compares equal to the original pointer.
- No other guarantees are offered
请注意,即使在那一节中,也没有提及将 void*
转换为函数指针。
我不清楚为什么您的计算机没有将其报告为错误。
您可以使用
functionSteps[0] = filterEvenFoos;
如果filterEvenFoos
是正确的函数类型。如果 filterEvenFoos
的声明与预期类型不完全匹配,即一个不带参数的函数和 returns 一个 void*
,那么你也不能使用它。
这是可能的,但要正确使用语法有点冒险。如果您为回调函数类型使用 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;
}
Is this not possible in CPP?
严格来说,不可以,因为类型安全和其他管理函数原型的规则。但是,根据您的需要,该 C 代码可以移植到 C++。
首先需要注意的是void* fn();
在C中的函数签名在C++中是不一样的。在 C++ 中要获得相同的函数签名,您需要像这样引入 variadic arguments:void* fn(...);
,但是,应该注意的是,对于这样的函数签名,您不能可移植地访问可变参数。
在 C++ 中,void* fn();
与 C 中的 void* fn(void);
相同。为此,如果您的函数在 C 中有变量输入,您需要在 C++ 中使用可变参数列表。
例如,如果您的代码类似于以下 C 代码:
#include <stdio.h>
#define NUM_STEPS 3
static void* filterEvenFoos(void)
{
printf("42\n");
return NULL;
}
static void* timesFooByTwo(int val)
{
printf("%d\n", (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(×FooByTwo);
functionSteps.push_back(&mapFooToBar);
functionSteps[0](0);
functionSteps[1](0, 42);
functionSteps[2](0, 3.14, &main);
return 0;
}
您可能会注意到函数签名略有变化,以允许以可移植的方式访问每个函数中的可变参数。
如果您使用的是 C++11,您也可以使用 std::function
inside the vector
,但您仍然需要具有匹配的函数签名。
您也可以利用 类 和继承,或模板特化,但在您的场景中这些可能是极端的过度杀戮。
最后,它不是从 C 代码到 C++ 的直接端口,但它是可行的。
希望能帮到你。