.. Mars Documentation Copyright (C) 2013 Matt Giuca .. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. .. You should have received a copy of the GNU General Public License along with this program. If not, see . :mod:`struct` --- Native struct and union helpers ================================================= .. sectionauthor:: Matt Giuca .. moduleauthor:: Matt Giuca .. module:: struct :synopsis: Provides functions to help read and write fields of structs and unions when interfacing with native code. This module, designed for use in conjunction with the :mod:`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 `_. .. highlight:: c 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. }; .. highlight:: mars 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: * *gender* will always be at offset 0, since it is first. * *country* will be at offset 2, since it must be 2-byte aligned. So there will be a padding byte after *gender*. * *age* will be at offset 8, since it must be 8-byte aligned. So there will be 4 padding bytes after *country*. * *height* will be at offset 16, right after *age*. * There will be 4 padding bytes after *height*, to round the struct up to a multiple of 8 (due to the presence of the ``double`` earlier on). So the whole struct will have a size of 24 bytes. 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 :func:`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") .. highlight:: marscon Now, the :func:`sizeof_struct` and :func:`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 .. highlight:: mars If you have a pointer to such a struct, you can access a field using :func:`cptr_add`, and adding one of the field offsets. Or, you can use the convenience function :func:`struct_fieldptr` to do just that. If you are accessing an array of structs, you should use :func:`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 :func:`union_fieldoffset` or :func:`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). .. type:: AlignInfo :: 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). * *size*: The size of the type in bytes. Must be a multiple of *alignment*. * *alignment*: Elements of this type must be stored at an address which is a multiple of this number. Must be >0. .. constant:: aligninfo_cchar :: AlignInfo The alignment info for :type:`CChar`, for use with :func:`build_struct`. .. constant:: aligninfo_cshort :: AlignInfo The alignment info for :type:`CShort`, for use with :func:`build_struct`. .. constant:: aligninfo_cint :: AlignInfo The alignment info for :type:`CInt`, for use with :func:`build_struct`. .. constant:: aligninfo_cfloat :: AlignInfo The alignment info for :type:`CFloat`, for use with :func:`build_struct`. .. constant:: aligninfo_cdouble :: AlignInfo The alignment info for :type:`CDouble`, for use with :func:`build_struct`. .. constant:: aligninfo_cptr :: AlignInfo The alignment info for :type:`CPtr`, for use with :func:`build_struct`. .. type:: StructDef Stores the computed field offsets and size of a struct. .. function:: build_struct_prims(format :: Array(Num)) :: StructDef Builds a :type:`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 :type:`StructDef`. The subsequent operations are cheap lookups. Therefore, it is recommended that you call :func:`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 :func:`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`` | :type:`CChar` | +------------------+------------+-----------------+ | ``h`` | ``short`` | :type:`CShort` | +------------------+------------+-----------------+ | ``i`` | ``int`` | :type:`CInt` | +------------------+------------+-----------------+ | ``f`` | ``float`` | :type:`CFloat` | +------------------+------------+-----------------+ | ``d`` | ``double`` | :type:`CDouble` | +------------------+------------+-----------------+ | ``p`` | ``void*`` | :type:`CPtr` | +------------------+------------+-----------------+ .. function:: build_struct(fields :: Array(AlignInfo)) :: StructDef Builds a :type:`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 :func:`aligninfo_struct`. For a union type, pass the result of :func:`aligninfo_union`. .. highlight:: c For example, consider the following C struct definitions:: struct inner { char a; int b; }; struct outer { char x; char y; struct inner z; }; .. highlight:: mars 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``. .. function:: sizeof_struct(struct :: StructDef) :: Num Returns the size of a native struct, including any padding bytes. This is equivalent to the C expression applying ``sizeof`` to the struct type. .. function:: aligninfo_struct(struct :: StructDef) :: AlignInfo Returns the alignment info for a native struct, for use with :func:`build_struct`. .. function:: struct_fieldoffset(struct :: StructDef, fieldnum :: Num) :: Num 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. .. function:: struct_fieldptr(struct :: StructDef, pointer :: CPtr, fieldnum :: Num) :: CPtr 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))``. .. type:: UnionDef Stores the computed size of a union. .. function:: build_union_prims(format :: Array(Num)) :: UnionDef Builds a :type:`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 :type:`UnionDef`. The subsequent operations are cheap lookups. Therefore, it is recommended that you call :func:`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 :func:`build_struct_prims` for an explanation of this string's syntax. .. function:: build_union(fields :: Array(AlignInfo)) :: UnionDef Builds a :type:`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 :func:`build_struct` for more information. .. function:: sizeof_union(union :: UnionDef) :: Num Returns the size of a native union. This is equivalent to the C expression applying ``sizeof`` to the union type. .. function:: aligninfo_union(union :: UnionDef) :: AlignInfo Returns the alignment info for a union, for use with :func:`build_struct`.