将字符串从ECL传递给C ++

时间:2016-03-15 18:40:51

标签: common-lisp ecl

我试图进入嵌入在C ++中的Common Lisp的迷人世界。我的问题是我无法从c ++中读取和打印由ECL中定义的lisp函数返回的字符串。

在C ++中,我有这个函数来运行任意的Lisp表达式:

cl_object lisp(const std::string & call) {
    return cl_safe_eval(c_string_to_object(call.c_str()), Cnil, Cnil);
}

可以用这种方式做到

ECL:

(defun return-a-number () 5.2)

用C ++阅读和打印:

auto x = ecl_to_float(lisp("(return-a-number)"));
std::cout << "The number is " << x << std::endl;

一切都已设置并且工作正常,但我不知道用字符串而不是数字来做。这就是我的尝试:

ECL:

(defun return-a-string () "Hello")

C ++:

 cl_object y = lisp("(return-a-string)");
 std::cout << "A string: " << y << std::endl;

打印字符串的结果如下:

字符串:0x3188b00

我猜是字符串的地址。

这是捕获调试器和 y cl_object的内容。 y-&gt; string.self类型是一个ecl_character。

Debug

4 个答案:

答案 0 :(得分:5)

(从@ coredump的回答开始,string.self字段提供结果。)

string.self字段定义为类型ecl_character*(ecl / object.h),它似乎在ecl / config.h中以类型int给出(尽管我怀疑这个略有平台依赖)。因此,您将无法像打印字符一样打印它。

我发现对我有用的方法是将其重新解释为wchar_t(即一个unicode角色)。不幸的是,我有理由相信这不是可移植的,并且取决于如何配置ecl和C ++编译器。

// basic check that this should work
static_assert(sizeof(ecl_character)==sizeof(wchar_t),"sizes must be the same");

std::wcout << "A string: " << reinterpret_cast<wchar_t*>(y->string.self) << std::endl;
// prints hello, as required
// note the use of wcout

另一种方法是使用lisp类型base-string,它使用char(在lisp中为base-char)作为其字符类型。然后,lisp代码读取

(defun return-a-base-string ()
    (coerce "Hello" 'base-string))

(可能有更优雅的方式转换为base-string,但我不知道它们。)

用C ++打印

cl_object y2 = lisp("(return-a-base-string)");
std::cout << "Another: " << y2->base_string.self << std::endl;

(请注意,您不能在同一程序中混用wcoutcout

答案 1 :(得分:3)

根据2.6 StringsThe ECL Manual部分,我认为通过访问返回对象的string.self字段可以找到实际的字符数组。你能试试以下吗?

std::cout << y->string.self << std::endl;

答案 2 :(得分:2)

std::string str {""};    
cl_object y2 = lisp("(return-a-base-string)");
//get dimension
int j = y2->string.dim;
//get pointer
ecl_character* selv = y2->string.self;
//do simple pointer addition
for(int i=0;i<j;i++){
    str += (*(selv+i));
}
//do whatever you want to str

当从ecl_characters

构建字符串时,此代码有效

来自文档:

&#34; ECL定义了两种C类型来保存其字符:ecl_base_char和ecl_character。

当ECL是在没有Unicode的情况下构建的时,它们都重合并且通常匹配unsigned char,以覆盖所需的256个代码。 当使用Unicode构建ECL时,这两种类型不再等效,ecl_character更大。 为了使您的代码具有可移植性和面向未来的能力,请使用这两种类型来真正表达您的意图。&#34;

答案 3 :(得分:1)

在我的系统上,不需要return-a-base-string,但我认为添加兼容性可能会很好。我使用(ecl)嵌入式CLISP 16.1.2版本。 下面的代码从lisp中读取一个字符串并转换为C ++字符串类型--std :: string和c-string-并将它们存储在C ++变量中:

// strings initializations: string and c-string
std::string str2 {""};     
char str_c[99] = " ";
// text read from clisp, whatever clisp function that returns string type
cl_object cl_text = lisp("(coerce (text-from-lisp X) 'base-string)");
//cl_object cl_text = lisp("(text-from-lisp X)"); // no base string conversions
// catch dimension
int cl_text_dim = cl_text->string.dim;
// complete c-string char by char
for(int ind=0;i<cl_text_dim;i++){
str_c[i] = ecl_char(cl_text,i); // ecl function to get char from cl_object
   }
str_c[cl_text_dim] ='\0'; // end of the c-string
str2 = str_c; // get the string on the other string type
std::cout <<  "Dim: " << cl_ text_dim << " C-String var: " << str_c() << " String var << str2 << std::endl;   

通过char传递char是一个缓慢的过程,但这是我知道的唯一方法。希望能帮助到你。问候!