Add ability to force alignment of ctypes.Structure

Currently, there is no real way to create a ctypes.Structure which has some fixed minimum alignment.
It is easy to go the other way and set the maximum alignment by using the _pack_ attribute on the class, however for classes which you’d like to set a minimum alignment this is not possible at all it seems.

Consider the following example where we are trying to map some binary data to a structure, but one of the types comes from c++ where there struct is aligned to 16 bytes (IDString in this example).

class IDString(ctypes.Structure):
    _fields_ = [
        ("string", ctypes.c_char * 0x10),
    ]

class main(ctypes.Structure):
    _fields_ = [
        ("first", ctypes.c_uint32),
        ("second", ctypes.c_ubyte),
        ("string", IDString),
    ]

data = bytearray(
    b"\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21\x00\x00\x00\x00"
)
m = main.from_buffer(data)
print(f"first: {m.first}")  # first: 7
print(f"second: {m.second}")  # second: 1
print(f"string: {m.string.string}")  # string: b''

However, if we have a way to indicate how the ctypes.Structure should be aligned, such as:

class IDString(ctypes.Structure):
    _align_ = 0x10
    _fields_ = [
        ("string", ctypes.c_char * 0x10),
    ]
...
print(f"string: {m.string.string}")  # string: b'hello world!'

Then we would be able to easily map this data without needing to add any annoying padding bytes which may all have to manually calculated if the structs have many fields which have alignment like this.

I have already made a sample implementation to make sure it works as intended and so would love some community feedback on this new feature I am proposing.

I think it is reasonable since we support #pragma pack with the _pack_ attribute, so to support #pragma align with an _align_ attribute seems sensible. It is also backward compatible since not having the attribute will just work how it did before.

4 Likes

I like this idea. It reminds me of previous issues related to different packing/aligning depending on Windows vs Linux. Being able to force one across the board would be nice for interoperability.

1 Like

I’ve also lost hours debugging this kind of issues when doing low level stuff. I think it is really useful to have this implemented