duns1222@w203zrz.zrz.tu-berlin.de (Martin Dunschen) (03/06/91)
Hello everybody, I have a problem passing the address of an Eiffel feature to a foreign routine, written in C. In the case you want to pass the address of a simple feature, like a real, it seems to be no problem. Also, as given in the example $EIFFEL/examples/.../callbacks, comming along with version 2.3, it is possible to pass pointers to eiffel-routines. But how to pass pointers to complex features, like ARRAY[REAL] ? The reason, we want to do this, is the reuse of software, written in FORTRAN77. If you know this language, you can imagine that there is extensive use of fortran arrays, passed via parameterlists. Because Eiffel 2.3 does not know external clauses with language "Fortran", we use short C procedures, which call the Fortran subroutines. The argument passing and all other problems using C together with Fortran are already solved. To supply the Fortran subroutine with these arrays, or getting back the results of a computation on an array, we think about using the possibility of passing pointers of Eiffel features to foreign routines, this is descibed very brief in "Eiffel: The language (version 2.2)", pages 218, 219. Perhaps there is a workaround? Nevertheless I include a few C routines and eiffel-classes, showing in two examples what I mean. You cut this file at the indicating lines, put the parts in new files, named .eiffel, test.e, c_test.c for example 1 in one directory, and the others, with same names in another directory. Compile the C-routine in each directory and invoke es. The executable in example 1 does what I expect, example 2 is somehow a clue for me! Thanks in advance, Martin +-----------------------------------------------------------------+ | e-mail: dunschen@zrzsp9.fb12.tu-berlin.de | | dunschen@DB0TUS11.BITNET | | | | voice : +49.+30.31424109 | | fax : +49.+30.31426883 | +-----------------------------------------------------------------+ CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ -- -- Beginning of first example, following files are .eiffel, test.e, c_test.c -- ------------ EIFFEL SYSTEM DESCRIPTION FILE ------------------- -- For simple uses, just replace ``root_class_name'' below -- by the name of the root class of your system (lower case) ROOT: test UNIVERSE: $EIFFEL/library/structures $EIFFEL/library/support EXTERNAL: c_test.o NO_ASSERTION_CHECK (N): ALL PRECONDITIONS (Y): ALL ALL_ASSERTIONS (N): ALL DEBUG (N): TRACE (N): OPTIMIZE (N): ALL GARBAGE_COLLECTION (N) C_PACKAGE (N): C_EXTERNAL: MAKE: VISIBLE (N): CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ --| --| test.e --| class TEST feature value : REAL; Create is external c_test language "C" do value := 25.; io.putstring (" this is test.e value="); io.putreal (value); io.putstring ("\n"); c_test (@value); io.putstring (" this is test.e, after c_test value="); io.putreal (value); io.putstring ("\n"); end --create end -- class TEST CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ /* c_test.c */ c_test (parm) float *parm; { printf ("this is c_test, parm= %f \n", *parm); *parm = *parm +25.; } CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ -- -- Beginning of second example, following files are .eiffel, test.e, c_test.c -- ------------ EIFFEL SYSTEM DESCRIPTION FILE ------------------- -- For simple uses, just replace ``root_class_name'' below -- by the name of the root class of your system (lower case) ROOT: test UNIVERSE: $EIFFEL/library/structures $EIFFEL/library/support EXTERNAL: c_test.o NO_ASSERTION_CHECK (N): ALL PRECONDITIONS (Y): ALL ALL_ASSERTIONS (N): ALL DEBUG (N): TRACE (N): OPTIMIZE (N): ALL GARBAGE_COLLECTION (N) C_PACKAGE (N): C_EXTERNAL: MAKE: VISIBLE (N): CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ class TEST feature list : ARRAY[REAL]; Create is external c_test language "C" do list.create(0,2); list.put ( 10.,0); list.put ( 20.,1); list.put ( 30.,2); io.putstring ("test, before c_test:\n"); io.putreal (list.item (0)); io.putstring ("\n"); io.putreal (list.item (1)); io.putstring ("\n"); io.putreal (list.item (2)); io.putstring ("\n"); c_test (@list); io.putstring ("test, after c_test:\n"); io.putreal (list.item (0)); io.putstring ("\n"); io.putreal (list.item (1)); io.putstring ("\n"); io.putreal (list.item (2)); io.putstring ("\n"); end --create end -- class TEST CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------ c_test (list) float *list; { printf ("this is c_test, list(0)= %f \n", list[0]); printf (" list(1)= %f \n", list[1]); printf (" list(2)= %f \n", list[2]); list[0] = list [1] + list [2]; }
duns1222@w203zrz.zrz.tu-berlin.de (Martin Dunschen) (03/07/91)
This posting is especially to Greg Economides of Biosystems
Modelling Group at Texas A&M University, e-mail greg@carnivore.tamu.edu
BUT everybody interested, feel free to read on, perhaps read first my
posting from the day before, same subject!
Hi Greg,
I tried to send you a mail, but it turned out that your configuration
is not ready for receiving mail, so I try this way.
thank you for your help regarding our problems passing eiffel features
to foreign routines. I understand the main principle now.
You call the "methods", e. g. the features `item' and `put', from
within the C routine. For this you have to find them, depending on
the object, to which these features belong. In our example we
refer to the features `item' and `put' via the ROUT_PTR eif_rout.
We store the pointers to these features on the variables `put_ptr'
and `item_ptr' for further use.
Ok, so far so good, but I tried your code-examples, with a few minor
changes, and they didn't work. The following questions arose:
1. Do you pass an_array as it is or as @an_array ?
2. How to declare an_array in c_func, as Object or OBJPTR ?
3. How do I know the number/types of parameters to item_ptr and put_ptr?
Are they according to the syntax in an eiffel-program ?
4. How to declare myvar, as float, or as a pointer to something else ?
Again, I include eiffel and C code, what I got from you with some
changes. (Our C compiler seems not ANSI standardized !)
Excuse me, when I bother you again, but what can I do?
Bye, Martin
CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------
class WHATEVER
feature
an_array: ARRAY[REAL];
Create is
external c_func language "C"
do
an_array.Create ( 0, 2);
an_array.put (10.,0);
an_array.put (20.,1);
an_array.put (30.,2);
output ("before calling c_func:",
an_array.item(0),
an_array.item(1),
an_array.item(2));
c_func(@an_array);
-- c_func(an_array);
output ("after calling c_func:",
an_array.item(0),
an_array.item(1),
an_array.item(2));
end; -- a_feature
output (str: STRING; r1, r2, r3: REAL) is
do
io.putstring (str);
io.putreal (r1);
io.putstring (" ");
io.putreal (r2);
io.putstring (" ");
io.putreal (r3);
io.putstring ("\n")
end -- output
end; -- class WHATEVER
CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------
#include "/path/to/Eiffel/files/_eiffel.h"
void c_func (array_ptr)
OBJPTR array_ptr;
/* Object array_ptr */
{
extern ROUT_PTR eif_rout;
/* in the example /path/to/eiffel/examples/eiffel-c/callbacks
the previous declaration looks like
extern ROUT_PTR (*eif_rout)();
*/
ROUT_PTR put_ptr, item_ptr;
float myvar; /* is this correct? I'm not shure */
/* assigning the eiffel routines to variables `put_ptr' and `item_ptr'
is useful if these eiffel functions will be used more than once.
otherwise a one-time call can be made like this:
(*(eif_rout(array_ptr,"item")))(array_ptr, 3)
arguments to `item' -----^ */
printf ("in c_func, before assigning pointers to eif_rout's\n");
put_ptr = eif_rout(array_ptr, "put");
item_ptr = eif_rout(array_ptr, "item");
printf ("in c_func, after assigning pointers to eif_rout's\n");
/* Now, to use these pointers to eiffel functions */
printf ("in c_func, before calling item \n");
/* myvar = *(eif_rout(array_ptr,"item"))(array_ptr, 3); */
myvar = (*item_ptr)(array_ptr,3);
printf ("in c_func, after calling item, myvar=%f\n", myvar);
/* maybe you'd make a fortran call here which would change the value of
myvar.... and then you might want to put it back into the array */
myvar = myvar * 2.; /* just an example to change something */
printf ("in c_func, before calling put, myvar=%f\n", myvar);
/* (*(eif_rout(array_ptr,"item")))(array_ptr,myvar, 3); */
(*put_ptr)(array_ptr,myvar,3);
printf ("in c_func, after calling put, myvar=%f\n", myvar);
}