我想知道是否有某种方法可以从Common Lisp调用C ++代码(最好是可移植的,如果没有,最好是在SBCL中,如果没有,那么,那么Clozure,CLisp或ECL)。
C ++将在内部循环中调用以进行数值计算,因此如果调用速度很快就会很好。
CFFI似乎不支持这个:
“这个概念可以推广到 其他语言;在那个时间 写作,只有CFFI的C支持 相当完整,但C ++支持 正在努力。“
(手册第4章)
SBCL的手册也没有提到C ++;它实际上说
本章介绍SBCL C程序和库的接口 (并且,因为C接口是一种 Unix世界的通用语言,以及其他程序和库 一般。)
C ++代码使用OO和运算符重载,所以它确实需要用g ++编译。
据我所知,我可以使用C ++ main()函数并为C函数编写包装器,但不是相反 - 这是真的吗?
无论如何......有没有办法做到这一点?
谢谢!
答案 0 :(得分:17)
编译之后,大多数C ++函数实际上归结为常规C函数调用。由于函数重载和其他功能,C ++编译器使用name mangling来区分类似命名的函数。给定一个对象转储实用程序和关于C ++编译器的足够知识,您可以直接从外部世界调用C ++代码。
尽管如此,您可能会发现在Lisp和C ++代码之间编写C兼容层更容易。您可以使用extern "C"
这样做:
extern "C" Foo *new_Foo(int x)
{
return new Foo(x);
}
这使得new_Foo()
函数遵循C调用约定,以便您可以从外部源调用它。
答案 1 :(得分:13)
除了名称修改之外,调用C ++函数而不是C函数的主要区别在于隐藏传递给成员函数的 this 指针等“隐藏”功能。 C运行时层对这些,隐式类型转换和其他有趣的C ++特性一无所知,因此如果您打算通过C接口调用C ++,则可能必须在必要时伪造这些功能。
假设您至少可以为要调用的对象及其所需的数据保留void *,则可以降级以下C ++调用
matrix->multiply(avector);
如果你创建一个C包装函数,那么进行C调用:
extern "C"
void matrix_multiply(void *cpp_matrix, void *cpp_vector) {
reinterpret_cast<matrix_type *>(cpp_matrix)->multiply(reinterpret_cast<vector_type *>(cpp_vector);
}
显然,函数matrix_multiply将位于C ++源代码中并按原样编译,但它确实向外界公开了C接口。只要你可以与不透明指针进行交互,你就可以使用上面的翻译垫片了。
不可否认,对于像这样的问题,这不一定是最优雅的解决方案,但我过去在像你这样的情况下使用它。
另一种选择是直接通过将C ++调用视为带有附加参数的C调用并自己提供所有必需信息来直接进行C ++调用,但这确实可以让您快速进入特定于编译器的代码领域。基本上,您仍然会持有C ++对象的不透明指针,但您必须计算出要调用的函数的错位名称。一旦你有了这个函数名,就必须提供this指针(在C ++中是隐式的,在上面的例子中是隐式的)和正确的参数然后调用函数。它可以完成,但如上所述,让您深入了解编译器领域甚至编译器版本特定的行为。
答案 2 :(得分:6)
哦,等等!
似乎我可以使用trick!
我在C ++中编写了一个包装器,声明包装函数extern“C”:
#include "lib.h"
extern "C" int lib_operate (int i, double *x) {
...
}
可以从C和C ++调用的头文件lib.h是:
#if __cplusplus
extern "C" {
#endif
int lib_operate (int i, double *x);
#if __cplusplus
}
#endif
然后编译:
g++ -c lib.cpp
gcc -c prog.c
gcc lib.o prog.o -lstdc++ -o prog
似乎适合玩具示例! : - )
因此,在Common Lisp中,我在加载libstdc ++后调用包装器。
无论如何,谢谢你的答案!
答案 3 :(得分:3)
根据您的C ++ ABI,您的包装器(上面的lib_operate
)可能需要以某种方式处理可能发生的任何C ++异常。如果您的ABI执行表驱动器异常处理,则未处理的异常将使(Lisp)进程崩溃。如果它改为进行动态注册,您甚至可能不会注意到任何问题。无论哪种方式,都很糟糕。
或者,如果你已经获得了包装代码的无抛出保证,你可以忽略这一切。
答案 4 :(得分:1)
您可以使用cl-cxx,就像为python编写pybind11一样。
c ++'std> = c ++ 14'中的示例,编译为共享库:
#include <string>
#include "clcxx/clcxx.hpp"
class xx {
public:
xx(int xx, int yy) : y(yy), x(xx) {}
std::string greet() { return "Hello, World"; }
int y;
int x;
};
std::string greet() { return "Hello, World"; }
int Int(int x) { return x + 100; }
float Float(float y) { return y + 100.34; }
auto gr(std::complex<float> x) { return x; }
std::string hi(char* s) { return std::string("hi, " + std::string(s)); }
void ref_class(xx& x) { x.y = 1000000; }
CLCXX_PACKAGE TEST(clcxx::Package& pack) {
pack.defun("hi", &hi);
pack.defun("test-int", &Int);
pack.defun("greet", &greet);
pack.defun("test-float", &Float);
pack.defun("test-complex", &gr);
pack.defun("ref-class", &ref_class);
pack.defclass<xx, false>("xx")
.member("y", &xx::y)
.defmethod("greet-from-class", &xx::greet)
.constructor<int, int>();
}
使用Lisp:
(cffi:use-foreign-library my-lib)
(cxx:init)
(cxx:add-package "TEST" "TEST")
(test:greet)
(setf my-class (test:creat-xx2 10 20))
(test:y.get myclass)
这将为您完成所有转换,例如外部“ C”……。