【问题标题】:Define C++ function at runtime在运行时定义 C++ 函数
【发布时间】:2011-06-24 09:55:42
【问题描述】:

我正在尝试调整我编写的一些数学代码以允许使用任意函数,但我似乎只能通过在编译时预定义它们来做到这一点,这似乎很笨重。我目前正在使用函数指针,但据我所知,仿函数也会出现同样的问题。举一个简单的例子,对于前向差分,使用的代码是:

double xsquared(double x) {
    return x*x;
}

double expx(double x) {
    return exp(x);
}

double forward(double x, double h, double (*af)(double)) {
    double answer = (af(x+h)-af(x))/h;

    return answer;  
}

前两个函数中的任何一个都可以作为第三个参数传递。然而,我想做的是传递用户输入(在有效的 C++ 中),而不必事先设置函数。任何帮助将不胜感激!

【问题讨论】:

  • 那么您想构建一个功能齐全的 C++ 编译器吗?呃……我认为这有点超出了 Stack Overflow 的范围。
  • c++ 不是脚本语言...您可以尝试与 lua、tcl 或 python 之类的东西集成
  • 您使用了错误的语言。 (C++0x 确实有闭包等,但它可能仍然很笨重。)

标签: c++ function-pointers functor


【解决方案1】:

从历史上看,您要求的那种功能在 C++ 中不可用。通常的解决方法是为 C++ 以外的语言嵌入解释器(例如,Lua 和 Python 专门设计用于集成到 C/C++ 应用程序中以允许对它们进行脚本编写),或者使用您的应用程序创建特定于您的应用程序的新语言自己的解析器、编译器等。但是,这种情况正在改变。

Clang 是一种新的开源编译器,由 Apple 开发并利用 LLVM。 Clang 从一开始就被设计为不仅可以用作编译器,还可以用作可以嵌入到应用程序中的 C++ 库。我自己还没有尝试过,但是您应该能够使用 Clang 做您想做的事情——您可以将其链接为一个库并要求它编译您的用户输入到应用程序中的代码。

您可以尝试查看how the ClamAV team already did this, so that new virus definitions can be written in C

至于其他编译器,我知道 GCC 最近增加了对插件的支持。也许可以利用它来桥接 GCC 和您的应用程序,但由于 GCC 从一开始就不是为用作库而设计的,因此可能会更加困难。我不知道有任何其他编译器具有类似的能力。

【讨论】:

  • LLVM 支持 JIT 编译,这是这里的关键特性。除了 ClamAV,我知道还有一个为 CLang 编写解释器的项目。虽然不记得状态:)
  • @MatthieuM.:我想你在考虑Cling
  • @kirbyfan64sos:我确实是 :)
【解决方案2】:

由于 C++ 是一种完全编译的语言,除非您编写自己的编译器或解释器,否则您无法真正将用户输入转换为代码。但是在这个例子中,可以为特定领域语言构建一个简单的解释器,它可以是数学公式。一切都取决于你想做什么。

【讨论】:

  • 你现在可以用至少一个编译器来做到这一点,看看我的回答。
  • 知道了,谢谢。另一位用户将我指向 muParser,我可能会在最终代码中使用它,但我仍然有兴趣了解如何将我自己的方程解释器的结果传递给函数 - 任何机会简要说明?
  • @Greg 例如,您可以创建一个实现运算符 () (函数调用)的类,然后将调用委托给您的解释器,传入您从等式解析中获得的抽象语法树.
【解决方案3】:

您始终可以获取用户的输入并通过您的编译器运行它,然后执行生成的二进制文件。这当然会有安全风险,因为它们可以执行任意代码。

可能更简单的方法是设计一种极简语言,让用户定义简单的函数,用 C++ 解析它们以执行正确的代码。

【讨论】:

  • 谢谢!我以为我将不得不写一个评论指出执行用户提供的 C++ 代码是一个巨大的安全风险,但看起来你已经处理好了。我很高兴有人指出了这一点。
【解决方案4】:

最好的解决方案是使用像 lua 或 python 这样的嵌入式语言来完成这类任务。参见例如Selecting An Embedded Language 建议。

【讨论】:

    【解决方案5】:

    您可以使用 tiny C compiler 作为库 (libtcc)。

    它允许你在运行时编译任意代码并加载它,但它只适用于 C 而不是 C++。

    通常唯一的方法是:

    • 将代码传递给编译器并创建共享对象或 DLL
    • 加载此共享对象或 DLL
    • 使用此共享对象的函数。

    【讨论】:

      【解决方案6】:

      与 Perl 等其他一些语言不同,C++ 不能对自身进行运行时解释。

      您唯一的选择是允许用户编译小型共享库,这些共享库可以由您的应用程序在运行时动态加载。

      【讨论】:

        【解决方案7】:

        嗯,你可以做两件事:

        1. 充分利用 boost/C++0x lambda 并在运行时定义函数。

        2. 如果只需要数学公式,muParser 之类的库旨在将字符串转换为字节码,这可以看作是在运行时定义函数。

        【讨论】:

        • muParser 看起来非常适合这项工作,谢谢。不过,我想我仍然会尝试将自己的基本方程解释器放在一起,以帮助了解“幕后”正在发生的事情。
        【解决方案8】:

        虽然这似乎是一个打击,但有很多人为 c++ 和 c 编写了方程解析器和解释器,许多商业化的,许多有缺陷的,而且都像人群中的面孔一样不同。一个起点是大学生为后缀翻译器编写中缀。其中一些系统使用附上分组,然后将项目放在堆栈上,就像在旧的 HP STL 库中一样。我花了 30 秒找到了这个:

        http://www.speqmath.com/tutorials/expression_parser_cpp/index.html

        可能的搜索字符串:“gcc 'equation parser' infix to postfix”

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-06-02
          • 1970-01-01
          • 2021-04-15
          • 1970-01-01
          • 2017-11-14
          • 2015-07-06
          • 2016-05-28
          相关资源
          最近更新 更多