Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Structs and layout

A type lays its fields out the way C lays out a struct on the same platform. So a type with the same fields in the same order as a C struct has the same size and offsets, and C can fill one in, read one, or return one.

'' A type has C's struct layout, so C can fill one in or return one.
type DivResult
    as int32 quot
    as int32 rem_       '' a field cannot be named rem: rem is a comment
end type

extern "C"
    declare function div( byval num as int32, byval den as int32 ) _
                     as DivResult
end extern

var r = div( 47, 10 )
print "div( 47, 10 ): quot"; r.quot; ", rem"; r.rem_

'' Natural alignment: value starts on a 4-byte boundary, as in C.
type Natural
    as uint8 tag
    as int32 value
end type

'' field = 1 packs the fields, as C's #pragma pack( 1 ) does.
type Packed field = 1
    as uint8 tag
    as int32 value
end type

print "Natural: size"; sizeof( Natural ); _
      ", value at"; offsetof( Natural, value )
print "Packed:  size"; sizeof( Packed ); _
      ", value at"; offsetof( Packed, value )

'' A fixed-size zstring is an inline char array, like C's char[ 8 ].
type Record
    as zstring * 8 label
    as int32 id
end type
print "Record:  size"; sizeof( Record ); _
      ", id at"; offsetof( Record, id )

Output

div( 47, 10 ): quot 4, rem 7
Natural: size 8, value at 4
Packed:  size 5, value at 1
Record:  size 12, id at 8

C's div returns a div_t, a struct of two ints, by value. DivResult has the same two fields, so the declaration can say it returns a DivResult, and tiko passes it back by the platform's rules exactly as a C compiler would. The field names do not have to match C's, only the types and the order; rem is the one name that cannot be used, because rem starts a comment.

Alignment. Each field sits on a boundary of its own size, with padding before it where needed, and the whole type is rounded up to its largest alignment. That is why Natural is 8 bytes and not 5. offsetof( T, field ) gives a field's offset, to check against the C header.

Packing. field = 1 removes the padding, as C's #pragma pack( 1 ) does; field = 2 and field = 4 limit the alignment the same way. Use them only to match a C struct that is packed. An unpacked C struct read through a packed type is garbage.

A fixed-size zstring * n is an inline array of n characters, like C's char name[ n ]. A ustring field is not: it holds a pointer to its text, and never belongs in a struct that C will read.

Activities

  1. Add an int64 field after value in Natural and predict the new size.
  2. Declare C's lldiv, which returns two long longs, and call it.