Next: , Previous: External modules, Up: C and Smalltalk

5.2 Using the C callout mechanism

To use the C callout mechanism, you first need to inform Smalltalk about the C functions that you wish to call. You currently need to do this in two places: 1) you need to establish the mapping between your C function's address and the name that you wish to refer to it by, and 2) define that function along with how the argument objects should be mapped to C data types to the Smalltalk interpreter. As an example, let us use the pre-defined (to gnu Smalltalk) functions of system and getenv.

First, the mapping between these functions and string names for the functions needs to be established in your module. If you are writing an external Smalltalk module (which can look at Smalltalk objects and manipulate them), see Linking your libraries to the virtual machine; if you are using function from a dynamically loaded library, see Dynamic loading.

Second, we need to define a method that will invoke these C functions and describe its arguments to the Smalltalk runtime system. Such a method is defined with a primitive-like syntax, similar to the following example (taken from kernel/

     system: aString
         <cCall: 'system' returning: #int args: #(#string)>
     getenv: aString
         <cCall: 'getenv' returning: #string args: #(#string)>

These methods were defined on class SystemDictionary, so that we would invoke it thus:

        Smalltalk system: 'lpr README' !

However, there is no special significance to which class receives the method; it could have just as well been Float, but it might look kind of strange to see:

        1701.0 system: 'mail' !

The various keyword arguments are described below.

cCall: 'system'
This says that we are defining the C function system. This name must be exactly the same as the string passed to defineCFunc.

The name of the method does not have to match the name of the C function; we could have just as easily defined the selector to be 'rambo: fooFoo'; it's just good practice to define the method with a similar name and the argument names to reflect the data types that should be passed.

returning: #int
This defines the C data type that will be returned. It is converted to the corresponding Smalltalk data type. The set of valid return types is:
Single C character value
A C char *, converted to a Smalltalk string
A C char *, converted to a Smalltalk string and then freed.
A C char *, converted to a Smalltalk symbol
A C char *, converted to a Smalltalk symbol and then freed.
A C int value
A C unsigned int value
A C long value
A C unsigned long value
A C double, converted to an instance of FloatD
A C long double, converted to an instance of FloatQ
No returned value (self returned from Smalltalk)
Single C wide character (wchar_t) value
Wide C string (wchar_t *), converted to a UnicodeString
Wide C string (wchar_t *), converted to a UnicodeString and then freed
An anonymous C pointer; useful to pass back to some C function later
An anonymous (to C) Smalltalk object pointer; should have been passed to C at some point in the past or created by the program by calling other public gnu Smalltalk functions (see Smalltalk types).
You can pass an instance of CType or one of its subclasses (see C data types). In this case the object will be sent #narrow before being returned: an example of this feature is given in the experimental Gtk+ bindings.

args: #(string)
This is an array of symbols that describes the types of the arguments in order. For example, to specify a call to open(2), the arguments might look something like:
             args: #(string int int)

The following argument types are supported; see above for details.

Smalltalk will make the best conversion that it can guess for this object; see the mapping table below
passed as char, which is promoted to int
passed as char, which is promoted to int
passed as wchar_t
passed as char *
passed as char *, the contents are expected to be overwritten with a new C string, and the object that was passed becomes the new string on return
passed as wchar_t *
passed as wchar_t *, the contents are expected to be overwritten with a new C wide string, and the object that was passed becomes the new string on return
passed as char *
passed as char *, even though may contain NUL's
passed as int
passed as unsigned int
passed as long
passed as unsigned long
passed as double
passed as long double
C object value passed as void *.

Any class with non-pointer indexed instance variables can be passed as a #cObject, and GNU Smalltalk will pass the address of the first indexed instance variable. This however should never be done for functions that allocate objects, call back into Smalltalk code or otherwise may cause a garbage collection: after a GC, pointers passed as #cObject may be invalidated. In this case, it is safer to pass every object as #smalltalk, or to only pass CObjects that were returned by a C function previously.

In addition, #cObject can be used for function pointers. These are instances of CCallable or one of its subclasses. See Smalltalk callbacks for more information on how to create function pointers for Smalltalk blocks.

Pointer to C object value passed as void **. The CObject is modified on output to reflect the value stored into the passed object.
Pass the object pointer to C. The C routine should treat the value as a pointer to anonymous storage. This pointer can be returned to Smalltalk at some later point in time.
an Array is expected, each of the elements of the array will be converted like an unknown parameter if variadic is used, or passed as a raw object pointer for variadicSmalltalk.
Pass the receiver, converting it to C like an unknown parameter if self is used or passing the raw object pointer for selfSmalltalk. Parameters passed this way don't map to the message's arguments, instead they map to the message's receiver.

Table of parameter conversions:

Declared param type Object type C parameter type used
boolean Boolean (True, False)int
byteArray ByteArray char *
cObject CObject void *
cObject ByteArray, etc. void *
cObjectPtr CObject void **
char Boolean (True, False)int
char Character int (C promotion rule)
char Integer int
double Float double (C promotion)
longDouble Float long double
int Boolean (True, False)int
int Integer int
uInt Boolean (True, False)unsigned int
uInt Integer unsigned int
long Boolean (True, False)long
long Integer long
uLong Boolean (True, False)unsigned long
uLong Integer unsigned long
smalltalk, selfSmalltalk anything OOP
string String char *
string Symbol char *
stringOut String char *
symbol Symbol char *
unknown, self Boolean (True, False)int
unknown, self ByteArray char *
unknown, self CObject void *
unknown, self Character int
unknown, self Float double
unknown, self Integer long
unknown, self String char *
unknown, self Symbol char *
unknown, self anything else OOP
variadic Array each element is passed according to "unknown"
variadicSmalltalk Array each element is passed as an OOP
wchar Character wchar_t
wstring UnicodeString wchar_t *
wstringOut UnicodeString wchar_t *

When your call-out returns #void, depending on your application you might consider using asynchronous call-outs. These are call-outs that do not suspend the process that initiated them, so the process might be scheduled again, executing the code that follows the call-out, during the execution of the call-out itself. This is particularly handy when writing event loops (the most common place where you call back into Smalltalk) because then you can handle events that arrive during the handling of an outer event before the outer event's processing has ended. Depending on your application this might be correct or not, of course. In the future, asynchronous call-outs might be started into a separate thread.

An asynchronous call-out is defined using an alternate primitive-like syntax, asyncCCall:args:. Note that the returned value parameter is missing because an asynchronous call-out always returns nil.