You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: SKILL.md
+27Lines changed: 27 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,6 +43,7 @@ from libdestruct import (
43
43
tagged_union, # tagged union field descriptor
44
44
offset, # explicit field offset
45
45
size_of, # get size in bytes of any type/instance/field
46
+
alignment_of, # get natural alignment of any type/instance
46
47
)
47
48
```
48
49
@@ -245,6 +246,32 @@ class message_t(struct):
245
246
246
247
The discriminator field must appear before the union. The union size is the max of all variant sizes. Struct variant fields are accessible directly: `msg.payload.x.value`. Use `.variant` to get the raw variant object. Unknown discriminator values raise `ValueError`.
247
248
249
+
### Struct Alignment
250
+
251
+
```python
252
+
# Default: packed (no padding)
253
+
classpacked_t(struct):
254
+
a: c_char
255
+
b: c_int
256
+
# size: 5
257
+
258
+
# Aligned: natural C alignment with padding
259
+
classaligned_t(struct):
260
+
_aligned_ =True
261
+
a: c_char
262
+
b: c_int
263
+
# size: 8 (1 + 3 padding + 4)
264
+
265
+
alignment_of(c_int) # 4
266
+
alignment_of(aligned_t) # 4 (max member alignment)
By default, libdestruct structs are **packed** — fields are placed sequentially with no padding, like C structs with `__attribute__((packed))`.
4
+
5
+
You can opt into natural alignment (matching standard C struct layout) by setting `_aligned_ = True` on your struct:
6
+
7
+
## Enabling Alignment
8
+
9
+
```python
10
+
from libdestruct import struct, c_char, c_int, c_long, size_of
11
+
12
+
classpacked_t(struct):
13
+
a: c_char
14
+
b: c_int
15
+
16
+
size_of(packed_t) # 5 (1 + 4, no padding)
17
+
18
+
classaligned_t(struct):
19
+
_aligned_ =True
20
+
a: c_char
21
+
b: c_int
22
+
23
+
size_of(aligned_t) # 8 (1 + 3 padding + 4)
24
+
```
25
+
26
+
## Alignment Rules
27
+
28
+
When `_aligned_ = True`:
29
+
30
+
1.**Field alignment**: Each field is placed at an offset that is a multiple of its natural alignment (1 for `c_char`, 2 for `c_short`, 4 for `c_int`/`c_float`, 8 for `c_long`/`c_double`/`ptr`).
31
+
2.**Tail padding**: The struct's total size is rounded up to a multiple of the struct's alignment (the maximum alignment of any member).
32
+
33
+
```python
34
+
classmixed_t(struct):
35
+
_aligned_ =True
36
+
a: c_char # offset 0, size 1
37
+
b: c_short # offset 2 (aligned to 2), size 2
38
+
c: c_char # offset 4, size 1
39
+
d: c_int # offset 8 (aligned to 4), size 4
40
+
e: c_char # offset 12, size 1
41
+
f: c_long # offset 16 (aligned to 8), size 8
42
+
43
+
size_of(mixed_t) # 24 (padded to 8-byte boundary)
44
+
```
45
+
46
+
## Reading Aligned Structs
47
+
48
+
```python
49
+
import struct as pystruct
50
+
from libdestruct import inflater
51
+
52
+
classheader_t(struct):
53
+
_aligned_ =True
54
+
flags: c_char
55
+
size: c_int
56
+
57
+
# flags at offset 0, 3 bytes padding, size at offset 4
Alignment is respected for nested structs too. A nested struct's alignment equals the maximum alignment of its own members:
68
+
69
+
```python
70
+
classinner_t(struct):
71
+
_aligned_ =True
72
+
a: c_char
73
+
b: c_int
74
+
75
+
classouter_t(struct):
76
+
_aligned_ =True
77
+
x: c_char
78
+
inner: inner_t # aligned to 4 (inner's max member alignment)
79
+
80
+
size_of(inner_t) # 8
81
+
size_of(outer_t) # 12 (1 + 3 padding + 8)
82
+
```
83
+
84
+
## Custom Alignment Width
85
+
86
+
Set `_aligned_` to an integer to enforce a minimum alignment boundary. Fields still use natural alignment, but the struct's total size is padded to the specified boundary:
87
+
88
+
```python
89
+
classwide_t(struct):
90
+
_aligned_ =16
91
+
a: c_int
92
+
93
+
size_of(wide_t) # 16 (4 bytes data, padded to 16-byte boundary)
94
+
alignment_of(wide_t) # 16
95
+
```
96
+
97
+
`_aligned_ = True` is equivalent to using the maximum natural member alignment (up to 8).
98
+
99
+
## Interaction with Explicit Offsets
100
+
101
+
When a field has an explicit `offset()`, alignment does **not** override the specified position. Alignment resumes for subsequent fields without explicit offsets:
102
+
103
+
```python
104
+
from libdestruct import offset
105
+
106
+
classs_t(struct):
107
+
_aligned_ =True
108
+
a: c_char
109
+
b: c_int = offset(3) # placed at offset 3, not rounded to 4
110
+
c: c_int # aligned normally after b
111
+
112
+
size_of(s_t) # 7 (3 + 4)
113
+
```
114
+
115
+
## alignment_of()
116
+
117
+
Use `alignment_of()` to query the alignment requirement of any type:
118
+
119
+
```python
120
+
from libdestruct import alignment_of, c_int, c_long
121
+
122
+
alignment_of(c_int) # 4
123
+
alignment_of(c_long) # 8
124
+
alignment_of(aligned_t) # max member alignment
125
+
alignment_of(packed_t) # 1 (packed structs have alignment 1)
0 commit comments