This chapter describes interfacing with ANSI C , X3.159-1989. See Overall Organization, section 14.1 for a short overview of the C interface functionality. See Built-in C classes, section 14.2 for a introducion on built-in C types provided by the extended Sather library. In User-defined External C types, section 14.3 you find information about user defined external C types, constants, attributes, and shared elements. Parameter Passing, section 14.4 covers parameter passing issues, and finally Inlining C Code, section 14.5 describes the inline C facility.
An external class which interfaces to ANSI C is designated with the language identifier 'C'. Types defined by external C classes are called external C types. Similar to external Fortran types, signatures without bodies (abstract signatures) are allowed in external C types. Such signatures must contain only built-in or user defined C types and they are implemented externally in ANSI C. Abstract iterator signatures are not allowed in external C classes. Routines with bodies whose signatures contain only C types may be called from C. Routines with bodies whose signatures use types other than C types are regular Sather routines and are not accessible from C. External C routines cannot be overloaded.
In contrast with the external Fortran classes, external C classes may have attributes and objects of external C types may exist. All attributes must also be of C types. The C interface provides a naming facility that allows interoperability with the existing C header files.
Global C variables can be accessed as shared attributes of external C classes.
C symbols are generated by applying a platform specific C name binding convention to the textual external C routine names. It is also possible to explicitly specify name binding for external C classes.
Finally, it is possible to inline ANSI C code into Sather sources. This allows for even greater flexibility in achieving Sather/C interoperability.
The following C types are built into the extended library:
Sather Class ANSI C type ------------------------------------- C_CHAR char C_CHAR_PTR char * C_UNSIGNED_CHAR unsigned char C_UNSIGNED_CHAR_PTR unsigned char * C_SIGNED_CHAR signed char C_SIGNED_CHAR_PTR signed char * C_SHORT short C_SHORT_PTR short * C_INT int C_INT_PTR int * C_LONG long C_LONG_PTR long * C_UNSIGNED_SHORT unsigned short C_UNSIGNED_SHORT_PTR unsigned short * C_UNSIGNED_INT unsigned int C_UNSIGNED_INT_PTR unsigned int * C_UNSIGNED_LONG signed long C_UNSIGNED_LONG_PTR unsigned long * C_FLOAT float C_FLOAT_PTR float * C_DOUBLE double C_DOUBLE_PTR double * C_LONG_DOUBLE long double C_LONG_DOUBLE_PTR long double * C_PTR void * C_PTRDIFF_T ptrdiff_t C_SIZE_T size_t
Variable of the built-in types are binary compatible with the corresponding C types. These classes define appropriate creation routines which may be used for convenient casting between Sather and C types. Also, many basic operations on the built-in C types are provided by the library. For example, it is not necessary to call external C code to add two C_INT variables. All operations on built-in C types defined by the library have the ANSI C semantics. Syntactic sugar for the built-in C types is defined exactly as for "regular" Sather classes.
-- "basic" operations may be done in Sather a:C_LONG := #(10); b:C_LONG := #(5); c::= a + b; #OUT + c.str + " should be 15\n";
'AREF{T}' defines a routine 'array_ptr:C_PTR' which may be used to obtain a pointer to the first item in the array portion of Sather objects. The external routine may modify the contents of this array portion, but must not store the pointer; there is no guarantee that the pointer will remain valid after the external routine returns. This restriction ensures that the Sather type system and garbage collector will not be corrupted by external code while not sacrificing efficiency for the most important cases.
The following example shows how a Sather array could be passed to external C functions:
/* ANSI C prototypes for functions called from Sather */ void clear(void* p, int size); void better_clear(int *, int size); external C class PROCESS_ARRAYS is -- routines implemented externally in C that zero -- all elements in an integer array of a specified size clear(p:C_PTR, size:C_INT); better_clear(p:C_INT_PTR, size:C_INT); end; -- This code demonstrates how to call external C routines a:ARRAY{INT} := #(10); -- this call just passes an array portion and avoids typecheking -- This is not recommended ("a" could be of type ARRAY{CHAR} and the -- call would still compile resulting in a runtime error) PROCESS_ARRAYS::clear(a.arr_ptr, #(a.size); -- this is a better sequence achieving the same result -- if "a" is not an array of integers, an error is reported PROCESS_ARRAYS::better_clear(#C_INT_PTR(a), #(a.size));
The second call is type-safe. It exploits the constructor for C_INT_PTR that allows creation from ARRAY{INT}.
User-defined external C classes are used for multiple purposes. C routines in external C classes implement Sather/C and C/Sather call interfaces. In addition, objects of external C types could be created and passed to or received from C. C global variables are accessed from Sather as shared attributes of external C classes.
Constants are allowed in external C classes. The rules for constant initialization are the same as for constants in "regular" Sather classes.
There are two constant features of external C classes that have a special semantics. If present, the STR constant 'C_name' may be used to force a particular C declaration for an external C type. Similarly the STR constant 'C_header' may be used to specify a list of C header files that should be included in each file in which the C declaration appears.
The STR constant 'C_name' provides a C binding name for the type in which it occurs. The STR constant 'C_header' must be initialized to a space separated list of header files (the standard C notation <foo.h> is allowed). Note that if constants C_name and C_header are absent, the Sather compiler generates layouts for the external C objects. If they are present, no layouts are generated and the necessary types must be defined in the specified header files. In this case, it is the responsibility of the programmer to ensure that attribute names are exactly as the structure filed names provided by the header files.
Examples
external C class BAR is attr bar_attr_int:C_INT; attr bar_attr_float:C_FLOAT; -- the constructor is defined in C create_bar:BAR; -- this routine that does some processing of bar is also -- defined in C process_bar(bar:BAR); end; -- create an object of type BAR by calling an external -- C constructor bar:BAR := BAR::create_bar; -- now pass "bar" back to C from processing BAR::process_bar(bar);
In this example, the Sather compiler generates the layout for the external objec BARt. The corresponding C layout and prototypes of C functions that are called from Sather are below:
typedef struct { int integer_field; float float_field; } *C_BAR; /* Note that C names for the type and struct fields could be different from the corresponding names in Sather */ C_BAR create_bar(); void process_bar(C_BAR bar);
This is a similar example, but an existing C header file is used with Sather code:
external C class BAR is const C_name:STR := "C_BAR"; -- C binding name for the type const C_header:STR := "bar.h <stdlib.h>"; attr integer_field:C_INT; attr float_field:C_FLOAT; -- the constructor is defined in C create_bar:BAR; -- this routine that does some processing of bar is also -- defined in C process_bar(bar:BAR); end; -- code that creates an object of type BAR by calling an external -- C constructor and then passes the object back to C bar:BAR := BAR::create_bar; -- now pass "bar" back to C from processing BAR::process_bar(bar);
The C header "bar.h" contains the following:
typedef struct { int integer_field; float float_field; } *C_BAR; /* Note that C names for the type must be exactly as the binding C name specified by the C_name attribute. also, struct field names must be exactly the same as attribute names in the external C class*/ C_BAR create_bar(); void process_bar(C_BAR bar);
This creates a Sather type 'X_WIDGET' which may be used to declare variables, parameterize classes, and so forth. Furthermore, the C declaration used for variables of type 'X_WIDGET' will be 'struct XSomeWidget *'. Any generated C file containing any variable of this type will also include '<widgets.h>'
external C class X_WIDGET is const C_name:STR := "struct XSomeWidget *"; const C_header:STR := "<widgets.h>"; end; -- external class X_WIDGET
Attributes and C structs
Attributes may be placed in external C classes; they are interpreted as fields of a C struct. If the layout of the class is generated by Sather (C_name and C_header symbolic constants are absent), then attributes can have any names. If a C layout from a header file specified by C_header is used, attribute textual names must be exactly the same as a struct filed names from a corresponding C type. It is the responsibility of the programmer to ensure this correspondence.
Points to note
Global C variables may be accessed from Sather as shared attributes of external C classes. Such shared attributes must have names corresponding to those of C globals. Similar to constants, shared attributes do not contribute to the storage needed to layout the class objects.
external C class FOO is C_name:STR := "FOO"; C_header:STR := "foo.h"; shared foo:FOO: attr val:C_INT; -- this is implemented in C create_foo:FOO; end; -- accessing a global C variable FOO::foo := FOO::create_foo; FOO::foo.val := #(10);
#ifndef _FOO_H_ #define _FOO_H_ typedef struct { int val; } *FOO; FOO create_foo(); #endif _FOO_H_
/* in some C file */ FOO foo;
The ANSI C standard prescribes that a copy is made of each call argument and all argument-passing is done strictly by value. To conform to ANSI C, all "in" arguments are passed by value. In the case of the built-in C types, a copy of a variable is passed. In the case of user defined external C types, a pointer to the object is copied and passed by value.
In addition, for extra flexibility, Sather supports "out" and "inout" argument modes for external C routines. "out" and "inout" arguments are passed by a pointer to a local, which may be legally modified by the called routine. The Sather implementation guarantee that such modifications cannot be observed until the routine returns. For C routines called from Sather this is guaranteed by emitting special code for the caller. For Sather routines that may be called from C, this is guaranteed by emitting special function prologues for the callee.
Sometimes it isn't possible to decide at the time the external C class is written whether a routine will be implemented in the C code with a macro. This presents a portability problem, because the writer of the external class can't know ahead of time whether the routine will be obtained by linking or by a header file. Such petulant cases can be dealt with by the call 'SYS::inlined_C'. The argument must be a string literal, and is placed directly into the generated code, except that identifiers following '#' that correspond to locals and arguments are translated into the appropriate C names.