Back: C callout Up: C and Smalltalk Forward: Smalltalk types   Top: GNU Smalltalk User's Guide Contents: Table of Contents Index: About: About this document

5.3 The C data type manipulation system

CType is a class used to represent C data types themselves (no storage, just the type). There are subclasses called things like CmumbleCType. The instances can answer their size and alignment. Their valueType is the underlying type of data. It's either an integer, which is interpreted by the interpreter as the scalar type, or the underlying element type, which is another CType subclass instance.

To make life easier, there are global variables which hold onto instances of CScalarCType: they are called CmumbleType (like CIntType, not like CIntCType), and can be used wherever a C datatype is used. If you had an array of strings, the elements would be CStringType's (a specific instance of CScalarCType).

CObject is the base class of the instances of C data. It has a subclass called CScalar, which has subclasses called Cmumble. These subclasses can answer size and alignment information.

Instances of CObject holds a pointer to a C type variable. The variable can be allocated from Smalltalk by doing type new, where type is a CType subclass instance, or it may have been returned through the C callout mechanism as a return value. Remember that CObject and its subclasses represent a pointer to a C object and as such provide the full range of operations supported by C pointers.

For example, + anInteger which returns a CObject which is higher in memory by anInteger times the size of each item. There is also - which acts like + if it is given an integer as its parameter. If a CObject is given, it returns the difference between the two pointers. incr, decr, incrBy:, decrBy: adjust the string either forward or backward, by either 1 or n characters. Only the pointer to the string is changed; the actual characters in the string remain untouched.

CObjects can be divided into two families, scalars and non-scalars, just like C data types. Scalars fetch a Smalltalk object when sent the value message, and change their value when sent the value: message. Non-scalars do not support these two messages.

replaceWith: aString replaces the string the instance points to with the new string. Actually, it copies the bytes from the Smalltalk String instance aString into the C string object, and null terminates. Be sure that the C string has enough room! You can also use a Smalltalk ByteArray as the data source.

Non-scalars include instances of CArray, CPtr and subclasses of CStruct and CUnion.

CPtrs and CArrays get their underlying element type through a CType subclass instance which is associated with the CArray or CPtr instance.

CPtr's also have value and value: which get or change the underlying value that's pointed to. In practice, value dereferences the pointer. CString is a subclass that answers a Smalltalk String when sent value, and automatically allocates storage to copy and null-terminate a Smalltalk String when sent value:.

Note that a CPtr to long points to a place in memory where a pointer to long is stored. In other words it is really a long ** and must be dereferenced twice with cPtr value value to get the long.

Finally, there are CStruct and CUnion, which are abstract subclasses of CObject(21). In the following I will refer to CStruct, but the same considerations apply to CUnion as well, with the only difference that CUnions of course implement the semantics of a C union.

These classes provide direct access to C data structures including

Here is an example struct decl in C:
 
struct audio_prinfo {
    unsigned    channels;
    unsigned    precision;
    unsigned    encoding;
    unsigned    gain;
    unsigned    port;
    unsigned    _xxx[4];
    unsigned    samples;
    unsigned    eof;
    unsigned char       pause;
    unsigned char       error;
    unsigned char       waiting;
    unsigned char       _ccc[3];
    unsigned char       open;
    unsigned char       active;
};

struct audio_info {
    audio_prinfo_t      play;
    audio_prinfo_t      record;
    unsigned    monitor_gain;
    unsigned    _yyy[4];
};

And here is a Smalltalk equivalent decision:
 
CStruct subclass: AudioPrinfo [
    <declaration: #( (#sampleRate #uLong)
                     (#channels #uLong)
                     (#precision #uLong)
                     (#encoding #uLong)
                     (#gain #uLong)
                     (#port #uLong)
                     (#xxx (#array #uLong 4))
                     (#samples #uLong)
                     (#eof #uLong)
                     (#pause #uChar)
                     (#error #uChar)
                     (#waiting #uChar)
                     (#ccc (#array #uChar 3))
                     (#open #uChar)
                     (#active #uChar))>

    <category: 'C interface-Audio'>
]

CStruct subclass: AudioInfo [
    <declaration: #( (#play #{AudioPrinfo} )
                     (#record #{AudioPrinfo} )
                     (#monitorGain #uLong)
                     (#yyy (#array #uLong 4)))>

    <category: 'C interface-Audio'>
]

This creates two new subclasses of CStruct called AudioPrinfo and AudioInfo, with the given fields. The syntax is the same as for creating standard subclasses, with the additional metadata declaration:. You can make C functions return CObjects that are instances of these classes by passing AudioPrinfo type as the parameter to the returning: keyword.

AudioPrinfo has methods defined on it like:
 
    #sampleRate
    #channels
    #precision
    #encoding

etc. These access the various data members. The array element accessors (xxx, ccc) just return a pointer to the array itself.

For simple scalar types, just list the type name after the variable. Here's the set of scalars names, as defined in `kernel/CStruct.st':
 
   #long                   CLong
   #uLong                  CULong
   #ulong                  CULong
   #byte                   CByte
   #char                   CChar
   #uChar                  CUChar
   #uchar                  CUChar
   #short                  CShort
   #uShort                 CUShort
   #ushort                 CUShort
   #int                    CInt
   #uInt                   CUInt
   #uint                   CUInt
   #float                  CFloat
   #double                 CDouble
   #longDouble             CLongDouble
   #string                 CString
   #smalltalk              CSmalltalk
   #{...}                  A given subclass of CObject

The #{...} syntax is not in the Blue Book, but it is present in GNU Smalltalk and other Smalltalks; it returns an Association object corresponding to a global variable.

To have a pointer to a type, use something like:
 
        (#example (#ptr #long))

To have an array pointer of size size, use:
 
        (#example (#array #string size))

Note that this maps to char *example[size] in C.

The objects returned by using the fields are CObjects; there is no implicit value fetching currently. For example, suppose you somehow got ahold of an instance of class AudioPrinfo as described above (the instance is a CObject subclass and points to a real C structure somewhere). Let's say you stored this object in variable audioInfo. To get the current gain value, do
 
    audioInfo gain value

to change the gain value in the structure, do
 
    audioInfo gain value: 255

The structure member message just answers a CObject instance, so you can hang onto it to directly refer to that structure member, or you can use the value or value: methods to access or change the value of the member.

Note that this is the same kind of access you get if you use the addressAt: method on CStrings or CArrays or CPtrs: they return a CObject which points to a C object of the right type and you need to use value and value: to access and modify the actual C variable.



Back: C callout Up: C and Smalltalk Forward: Smalltalk types   Top: GNU Smalltalk User's Guide Contents: Table of Contents Index: About: About this document


This document was generated on May, 22 2008 using texi2html