Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a string from ECL to C++

I'm trying to get into the fascinating world of Common Lisp embedded in C++. My problem is that I can't manage to read and print from c++ a string returned by a lisp function defined in ECL.

In C++ I have this function to run arbitrary Lisp expressions:

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

I can do it with a number in this way:

ECL:

(defun return-a-number () 5.2)

read and print in C++:

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

Everything is set and works fine, but I don't know to do it with a string instead of a number. This is what I have tried:

ECL:

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

C++:

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

And the result of printing the string is this:

A string: 0x3188b00

that I guess is the address of the string.

Here it is a capture of the debugger and the contents of the y cl_object. y->string.self type is an ecl_character.

Debug

like image 787
user6034704 Avatar asked Dec 14 '22 07:12

user6034704


1 Answers

(Starting from @coredump's answer that the string.self field provides the result.)

The string.self field is defined as type ecl_character* (ecl/object.h), which appears to be given in ecl/config.h as type int (although I suspect this is slightly platform dependent). Therefore, you will not be able to just print it as if it was a character array.

The way I found worked for me was to reinterpret it as a wchar_t (i.e. a unicode character). Unfortunately, I'm reasonably sure this isn't portable and depends both on how ecl is configured and the C++ compiler.

// 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

The alternative is to use the lisp type base-string which does use char (base-char in lisp) as its character type. The lisp code then reads

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

(there may be more elegant ways to do the conversion to base-string but I don't know them).

To print in C++

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

(note that you can't mix wcout and cout in the same program)

like image 115
DavidW Avatar answered May 26 '23 21:05

DavidW