This module, designed for use in conjunction with the native module, allows C structs and unions to be declared dynamically, to calculate the offset of struct fields and the size of structs and unions. This is useful for reading and writing struct fields, as well as indexing into arrays of structs and unions.
The major advantage to using this module is that it attempts to get field alignment right, inserting padding bytes where necessary to match the C compiler.
Note
We say “attempts to get alignment right” because alignment is hard. It varies across different architectures, platforms and compilers, and there are a lot of corner cases. If you find that the alignment is broken in a particular case, please file a bug report.
For example, consider the following C struct definition:
struct person
{
char gender; // Male or female.
short country; // Country ID number.
double age; // Years.
int height; // Centimetres.
};
Accessing the fields of this struct from Mars is non-trivial, due to padding. On 64-bit Linux, double has a size and alignment of 8, and int has a size and alignment of 4, so the following constraints apply:
However, on 32-bit Linux, double has 4-byte alignment, so you cannot assume these offsets. This module helps you calculate the correct offsets of struct fields with the correct alignment. To do so, simply call build_struct_prims with a string that denotes the primitive types of the struct fields, and store it in a global constant:
def struct_person :: StructDef = build_struct_prims("bhdi")
Now, the sizeof_struct and struct_fieldoffset functions can provide information about how to access struct fields:
?> struct_fieldoffset(struct_person, 0)
0
?> struct_fieldoffset(struct_person, 1)
2
?> struct_fieldoffset(struct_person, 2)
8
?> struct_fieldoffset(struct_person, 3)
16
?> sizeof_struct(struct_person)
24
If you have a pointer to such a struct, you can access a field using cptr_add, and adding one of the field offsets. Or, you can use the convenience function struct_fieldptr to do just that. If you are accessing an array of structs, you should use sizeof_struct to find an individual struct element of the array.
The same concept applies for unions, but they are much simpler. Because all elements of a union are found at offset 0, there is no union_fieldoffset or union_fieldptr function. However, you can still use this to compute the size of a union (simply the maximum size of all of the union’s fields).
AlignInfo(size :: Num, alignment :: Num)
Stores information about the size and alignment of a native type (either a primitive type, or a struct or union).
The alignment info for CChar, for use with build_struct.
The alignment info for CShort, for use with build_struct.
The alignment info for CInt, for use with build_struct.
The alignment info for CFloat, for use with build_struct.
The alignment info for CDouble, for use with build_struct.
The alignment info for CPtr, for use with build_struct.
Stores the computed field offsets and size of a struct.
Builds a StructDef for a struct with only primitive fields from a format string describing the fields of the native struct.
Note
This function does all the expensive work of computing the size and offsets, storing the result in the StructDef. The subsequent operations are cheap lookups. Therefore, it is recommended that you call build_struct_prims once for each C struct and store the result in a global constant for quick recall.
Warning
Do not use this to describe structs with structs inside them (flattening out the fields); this may produce incorrect alignment. Instead, use build_struct.
format is a string containing a character for each struct field. The character indicates the primitive type of the field, as shown in this table.
Format character | C type | Mars type |
---|---|---|
b | char | CChar |
h | short | CShort |
i | int | CInt |
f | float | CFloat |
d | double | CDouble |
p | void* | CPtr |
Builds a StructDef for a struct with arbitrary fields. This allows structs to be specified with fields of struct or union types.
fields is a list of alignment infos, each describing a field of primitive, struct, or union type. For a primitive type, pass the aligninfo_* constant for that type. For example, build_struct([aligninfo_int, aligninfo_char]) is equivalent to build_struct_prims("ib"). For a struct type, pass the result of aligninfo_struct. For a union type, pass the result of aligninfo_union.
For example, consider the following C struct definitions:
struct inner
{
char a;
int b;
};
struct outer
{
char x;
char y;
struct inner z;
};
This can be described in Mars as follows:
def struct_inner :: StructDef = build_struct_prims("bi")
def struct_outer :: StructDef = build_struct([aligninfo_cchar, aligninfo_cchar, aligninfo_struct(struct_inner)])
Note that you cannot simply write build_struct_prims("bbbi") because the inner struct must be aligned to a 4-byte boundary, even though it starts with a char.
Returns the size of a native struct, including any padding bytes. This is equivalent to the C expression applying sizeof to the struct type.
Returns the alignment info for a native struct, for use with build_struct.
Returns the offset of struct field number fieldnum within a native struct, in bytes. If p is a pointer to a value of the struct type, this is the number of bytes after p where the given field may be found.
Helper method for finding the pointer to a struct field fieldnum. If pointer is a pointer to a value of the struct type, this returns a pointer to the given field.
This is equivalent to cptr_add(pointer, struct_fieldoffset(struct, fieldnum)).
Stores the computed size of a union.
Builds a UnionDef for a union with only primitive fields from a format string describing the fields of the native union.
Note
This function does all the expensive work of computing the size, storing the result in the UnionDef. The subsequent operations are cheap lookups. Therefore, it is recommended that you call build_union_prims once for each C union and store the result in a global constant for quick recall.
format is a string containing a character for each union field. See build_struct_prims for an explanation of this string’s syntax.
Builds a UnionDef for a union with arbitrary fields. This allows unions to be specified with fields of struct or union types.
fields is a list of alignment infos, each describing a field of primitive, struct, or union type. See build_struct for more information.
Returns the size of a native union. This is equivalent to the C expression applying sizeof to the union type.
Returns the alignment info for a union, for use with build_struct.