C/C++ calls and callbacks

by Colin LeMahieu (modified: 2020 Aug 16)

Most existing examples on how to do external calls contain a lot of English explanation which can distract people, like myself, who learn by example. This is intended to be a compilable, terse example of how to call in and out of C/C++.

This is a C example: class APPLICATION create make feature -- Initialization make is -- Run application. do create callback c_set_routine (callback.routine) c_set_object ($callback) c_do_callback end callback: CALLABLE feature{NONE} c_set_routine (routine: POINTER) is external "C inline use %"application.h%"" alias "c_set_routine ($routine);" end c_set_object (obj: POINTER) is external "C inline use %"application.h%"" alias "c_set_object ($obj);" end c_do_callback is external "C inline use %"application.h%"" alias "c_do_callback();" end end -- class APPLICATION

class CALLABLE feature inside is local current_addr: POINTER do current_addr := $Current io.put_string ("We're inside at address: " + current_addr.to_integer_32.out) io.put_new_line end routine: POINTER is do result := $inside end end

application.h: #include "eif_eiffel.h" EIF_OBJECT obj = NULL; EIF_POINTER routine; void c_set_routine (EIF_POINTER routine_a) { routine = routine_a; } void c_set_object (EIF_REFERENCE obj_a) { if(obj != NULL) { eif_wean (obj); } obj = eif_protect (obj_a); } void c_do_callback () { ((void (*) (EIF_REFERENCE)) routine) (eif_access (obj)); }

This is a similar C++ example: class APPLICATION create make feature -- Initialization make is do create call cpp_obj := c_new c_set_routine (cpp_obj, call.routine) c_set_object (cpp_obj, $call) c_do_callback (cpp_obj) end cpp_obj: POINTER call: CALLABLE feature {NONE} c_new: POINTER is external "C++ inline use %"application.h%"" alias "[ return new test_class; ]" end c_set_routine (obj: POINTER routine: POINTER) is external "C++ inline use %"application.h%"" alias "((test_class *) ($obj))->c_set_routine ($routine);" end c_set_object (obj: POINTER e_obj: POINTER) is external "C++ inline use %"application.h%"" alias "((test_class *) ($obj))->c_set_object ((EIF_REFERENCE)$e_obj);" end c_do_callback (obj: POINTER) is external "C++ inline use %"application.h%"" alias "((test_class *) ($obj))->c_do_callback();" end end

class CALLABLE feature inside is local current_addr: POINTER do current_addr := $Current io.put_string ("We're inside at address: " + current_addr.to_integer_32.out) io.put_new_line end routine: POINTER is do result := $inside end end

application.h: #include "eif_eiffel.h" class test_class { public: test_class(); ~test_class(); EIF_OBJECT obj; EIF_POINTER routine; void c_set_object (EIF_REFERENCE obj_a); void c_set_routine (EIF_POINTER routine_a); void c_do_callback (); }; test_class::test_class() { } void test_class::c_set_object (EIF_REFERENCE obj_a) { if (obj != NULL) { eif_wean (obj); } obj = eif_protect (obj_a); } void test_class::c_set_routine (EIF_POINTER routine_a) { routine = routine_a; } void test_class::c_do_callback () { ((void (*) (EIF_REFERENCE)) routine) (eif_access (obj)); }

Comments
  • Patrick Ruckstuhl (16 years ago 19/6/2008)

    After having a problem with creating a STRING from a std::string (c++): Here's the solution

    cpp_get_text: STRING is -- Get some dummy text external "C++ inline use <string>" alias "[ std::string a = "dummy"; return RTMS(((char*)a.c_str())); "] end

    • Manu (16 years ago 20/6/2008)

      Note that RTMS is a macro and evaluate twice its argument, so for efficiency it should be:

      cpp_get_text: STRING is -- Get some dummy text external "C++ inline use <string>" alias "[ std::string a = "dummy"; char *c_str = (char*) a.c_str(); return RTMS(c_str); "] end

  • Seref Arikan (14 years ago 27/10/2010)

    What kind of configuration this example requires ?

    Greetings, Simply creating the files for c++ example does not let me compile the results in Eiffel Studio. The compiler complains that it can't find application.h There are other examples which refer to header files under Eiffel Studio setup dir, but I could not figure out if there is a configuration setting that'd make compiler find header file.

    So, are there any chances of getting the Eiffel Studio project dir for me, or could you please point me in the right direction to get this working?

    This example seems to be related to an issue I'm wrestling with at the moment.

    Kind regards Seref

    • Manu (14 years ago 27/10/2010)

      The file `application.h' is specified in that post, it is one of the text boxes.

      • Seref Arikan (14 years ago 27/10/2010)

        Thanks, I should have been clearer. I've used the .h file, but could not include it in Eiffel studio. Then I found out how to do it, and created a sample project using the code in this article. My problem is, Eiffel Studio can't compile this code. I get the following error:

        C1/Cobj1.o:big_file_C1_cpp.cpp:(.text+0xb2b): undefined reference to `operator new(unsigned int) collect2: ld returned 1 exit status make.exe": *** [callbacktest.exe] Error 1

        What I can't understand is, the header file declares a C++ class. Eiffel studio uses the C compiler, so I would not expect the C compiler to make use of a C++ header. This is the bit I'm failing to understand.

        Regards Seref