eiffelroom

articleC/C++ calls and callbacks

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));
}

patrickr's picture

After having a problem with

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

manus_eiffel's picture

Note that RTMS is a macro

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

about - contact