Jay*_*Jay 13 c c++ common-lisp
我想知道是否有某种方法可以从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函数编写包装器,但不是相反 - 这是真的吗?
无论如何......有没有办法做到这一点?
谢谢!
Gre*_*ill 17
编译之后,大多数C++函数实际上归结为常规的C函数调用.由于函数重载和其他功能,C++编译器使用名称修改来区分类似命名的函数.给定一个对象转储实用程序和关于C++编译器的足够知识,您可以直接从外部世界调用C++代码.
尽管如此,您可能会发现在Lisp和C++代码之间编写C兼容层更容易.你会这样使用extern "C"这样:
extern "C" Foo *new_Foo(int x)
{
return new Foo(x);
}
Run Code Online (Sandbox Code Playgroud)
这使得该new_Foo()函数遵循C调用约定,以便您可以从外部源调用它.
Tim*_*sch 13
除了名称修改之外,调用C++函数而不是C函数的主要区别在于隐藏传递给成员函数的"隐藏"特性,如此指针.C运行时层对这些,隐式类型转换和其他有趣的C++特性一无所知,因此如果您打算通过C接口调用C++,则可能必须伪造这些功能.
假设您至少可以为要调用的对象及其所需的数据保留void*,则可以降级以下C++调用
matrix->multiply(avector);
Run Code Online (Sandbox Code Playgroud)
如果您创建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);
}
Run Code Online (Sandbox Code Playgroud)
显然,函数matrix_multiply将位于C++源代码中并按原样编译,但它确实向外界公开了C接口.只要您可以与不透明指针进行交互,就可以使用上面的转换填充程序.
不可否认,对于像这样的问题,这不一定是最优雅的解决方案,但我过去在像你这样的情况下使用它.
另一种选择是通过将C++调用视为具有附加参数的C调用并自己提供所有必需信息来直接进行C++调用,但这确实可以非常快速地将您带入特定于编译器的代码领域.基本上,您仍然会持有C++对象的不透明指针,但您必须计算出要调用的函数的错位名称.一旦你有了这个函数名,就必须提供this指针(在C++中是隐式的,在上面的例子中是隐式的)和正确的参数然后调用函数.它可以完成,但如上所述,让您深入了解编译器领域甚至编译器版本特定的行为.
等一下!
似乎有一个技巧我可以使用!
我用C++编写了一个包装器,声明包装函数extern"C":
#include "lib.h"
extern "C" int lib_operate (int i, double *x) {
...
}
Run Code Online (Sandbox Code Playgroud)
头文件lib.h可以从C和C++中调用,它是:
#if __cplusplus
extern "C" {
#endif
int lib_operate (int i, double *x);
#if __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
然后编译:
g++ -c lib.cpp
gcc -c prog.c
gcc lib.o prog.o -lstdc++ -o prog
Run Code Online (Sandbox Code Playgroud)
似乎适合玩具的例子!:-)
所以,在Common Lisp中,我在加载libstdc ++之后调用包装器.
无论如何,谢谢你的答案!
2021 年更新:CL-CXX-JIT处理 lisp 方面的大部分工作。
例子:
(ql:quickload :cxx-jit)
(in-package cxx-jit)
(from '("<cmath>") 'import '("static_cast<double(*)(double)>(std::sin)" . "cpp-sin"))
(cpp-sin 0d0)
(from nil 'import "struct C{ auto hi(){return \"Hello, World\\n\";} auto bye(){return \"Bye\";} };" '("&C::bye" . "bye") '("&C::hi" . "hi") '("[](){static C x; return x;}" . "cc"))
(cc)
(hi *)
(bye **)
Run Code Online (Sandbox Code Playgroud)
您可以使用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>();
}
Run Code Online (Sandbox Code Playgroud)
在 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)
Run Code Online (Sandbox Code Playgroud)
这将处理所有转换,extern "C", ... 为您服务。