![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
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
long
(unsigned too)
short
(unsigned too)
char
(unsigned too) & byte type
double
, long double
, float
string
(NUL terminated char *, with special accessors)
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 CObject
s 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 |
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.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |