gpt4 book ai didi

c++ - 在 C++ 中动态创建函数调用

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:34:29 29 4
gpt4 key购买 nike

大家好我希望你们能帮我解决这个问题:

我目前正在为一种脚本语言实现解释器。该语言需要一个对 C 函数的本地调用接口(interface),就像 java 具有 JNI 一样。我的问题是,我想在不编写包装函数的情况下调用原始 C 函数,它将我的脚本语言的调用堆栈转换为 C 调用堆栈。这意味着,我需要一种方法来在运行时生成 C 函数的参数列表。示例:

void a(int a, int b) {
printf("function a called %d", a + b);
}

void b(double a, int b, double c) {
printf("function b called %f", a * b + c);
}

interpreter.registerNativeFunction("a", a);
interpreter.registerNativeFunction("b", b);

解释器应该能够调用函数,只需要知道我的脚本语言的函数原型(prototype):native void a(int a, int b);native void b(双 a, 整数 b, 双 c);

有什么方法可以在 C++ 中生成 C 函数调用堆栈,还是我必须使用汇编程序才能完成此任务。汇编程序是个问题,因为解释器几乎可以在任何平台上运行。

编辑:解决方案是使用 libffi,一个库,它处理许多不同平台和操作系统的调用堆栈创建。 libffi 也被一些著名的语言实现所使用,例如 cpython 和 openjdk。

编辑:@MatsPetersson 在我的代码中的某个地方,我有一个类似的方法:

void CInterpreter::CallNativeFunction(string name, vector<IValue> arguments, IReturnReference ret) {
// Call here correct native C function.
// this.nativeFunctions is a map which contains the function pointers.
}

编辑:感谢你的帮助!我将继续使用 libffi,并在所有需要的平台上对其进行测试。

最佳答案

是的,我们可以。不需要 FFI 库,对 C 调用没有限制,只有纯 C++11。

#include <iostream>
#include <list>
#include <iostream>
#include <boost/any.hpp>

template <typename T>
auto fetch_back(T& t) -> typename std::remove_reference<decltype(t.back())>::type
{
typename std::remove_reference<decltype(t.back())>::type ret = t.back();
t.pop_back();
return ret;
}

template <typename X>
struct any_ref_cast
{
X do_cast(boost::any y)
{
return boost::any_cast<X>(y);
}
};

template <typename X>
struct any_ref_cast<X&>
{
X& do_cast(boost::any y)
{
std::reference_wrapper<X> ref = boost::any_cast<std::reference_wrapper<X>>(y);
return ref.get();
}
};

template <typename X>
struct any_ref_cast<const X&>
{
const X& do_cast(boost::any y)
{
std::reference_wrapper<const X> ref = boost::any_cast<std::reference_wrapper<const X>>(y);
return ref.get();
}
};

template <typename Ret, typename...Arg>
Ret call (Ret (*func)(Arg...), std::list<boost::any> args)
{
if (sizeof...(Arg) != args.size())
throw "Argument number mismatch!";

return func(any_ref_cast<Arg>().do_cast(fetch_back(args))...);
}

int foo(int x, double y, const std::string& z, std::string& w)
{
std::cout << "foo called : " << x << " " << y << " " << z << " " << w << std::endl;
return 42;
}

试驾:

int main ()
{
std::list<boost::any> args;
args.push_back(1);
args.push_back(4.56);
const std::string yyy("abc");
std::string zzz("123");
args.push_back(std::cref(yyy));
args.push_back(std::ref(zzz));
call(foo, args);
}

读者练习:实现registerNativeFunction三个简单的步骤。

  1. 用纯 call 创建一个抽象基类接受 boost::any 列表的方法, 称之为 AbstractFunction
  2. 创建一个继承AbstractFunction 的可变参数类模板并添加一个指向具体类型函数的指针(或 std::function )。实现 call就该功能而言。
  3. 创建 map<string, AbstractFunction*> (实际使用智能指针)。

缺点:完全不能用这种方法调用可变的 C 风格函数(例如 printf 和 friend )。也不支持隐式参数转换。如果你传递一个 int到需要 double 的函数,它会抛出一个异常(这比你可以通过动态解决方案获得的核心转储稍微好一点)。通过专门化 any_ref_cast 可以部分解决有限固定转换集的问题.

关于c++ - 在 C++ 中动态创建函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26575303/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com