将字符串从 ECL 传递到 C++
Pass a string from ECL to C++
我正在尝试进入 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->string.self 类型是 ecl_character.
根据 2.6 Strings of The ECL Manual 部分,我认为实际的字符数组是通过访问返回对象的 string.self
字段找到的。您可以尝试以下方法吗?
std::cout << y->string.self << std::endl;
(从@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;
(注意不能在同一个程序中混用wcout
和cout
)
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
构建时,此代码有效
来自文档:
"ECL 定义了两个 C 类型来保存它的字符:ecl_base_char 和 ecl_character。
当在没有 Unicode 的情况下构建 ECL 时,它们都一致并且通常匹配 unsigned char,以涵盖所需的 256 个代码。
当使用 Unicode 构建 ECL 时,这两种类型不再等价,ecl_character 更大。
为了使您的代码具有可移植性和面向未来的能力,请使用这两种类型来真正表达您的意图。"
在我的系统上不需要 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] ='[=10=]'; // 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;
一个字符一个字符地传递是一个缓慢的过程,但据我所知,这是唯一的方法。希望能帮助到你。问候!
我正在尝试进入 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->string.self 类型是 ecl_character.
根据 2.6 Strings of The ECL Manual 部分,我认为实际的字符数组是通过访问返回对象的 string.self
字段找到的。您可以尝试以下方法吗?
std::cout << y->string.self << std::endl;
(从@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;
(注意不能在同一个程序中混用wcout
和cout
)
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
构建时,此代码有效来自文档:
"ECL 定义了两个 C 类型来保存它的字符:ecl_base_char 和 ecl_character。
当在没有 Unicode 的情况下构建 ECL 时,它们都一致并且通常匹配 unsigned char,以涵盖所需的 256 个代码。 当使用 Unicode 构建 ECL 时,这两种类型不再等价,ecl_character 更大。 为了使您的代码具有可移植性和面向未来的能力,请使用这两种类型来真正表达您的意图。"
在我的系统上不需要 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] ='[=10=]'; // 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;
一个字符一个字符地传递是一个缓慢的过程,但据我所知,这是唯一的方法。希望能帮助到你。问候!