Skip to content

Data Model

Model: LP64
Byte Order: little endian
Internal SP: 8-byte aligned
Function Entry: 2-byte aligned
Before CALL: SP mod 16 = 8
Aggregate Maximum Alignment: 16 bytes

Scalar Types

Reference C Data Model

Type Bits Align
_Bool 8 1
char 8 1
signed char 8 1
unsigned char 8 1
short 16 2
int 32 4
long 64 8
long long 64 8
__int128 128 16
unsigned __int128 128 16
ordinary pointer 64 8
size_t 64 8
ptrdiff_t 64 8
wchar_t 32 4
char16_t 16 2
char32_t 32 4
float 32 4
double 64 8
long double 64 8
float _Complex 64 4
double _Complex 128 8
long double _Complex 128 8

Scalar Type Semantics

The widths and natural alignments of scalar types are given in Table 3-1. The following rules define the type identities and representations that supplement those two values.

Integer types and aliases.

Plain char is signed. size_t is an alias for unsigned long, and ptrdiff_t is an alias for long. wchar_t is a signed 32-bit integer; char16_t and char32_t are unsigned 16-bit and 32-bit integers, respectively. In the absence of a separate enum extension, an enum has the representation, size, and alignment of int.

A stored _Bool has the integer value zero or one. False is encoded with every object-representation bit clear; true is encoded with bit 0 set and every other bit clear.

Ordinary pointers.

An ordinary object or function pointer is 64 bits wide and 8-byte aligned. Its value is a pre-segment coordinate. Object and function pointers remain distinct C type categories even though their baseline representations have the same size and alignment. The null pointer has numeric address zero and an all-zero 64-bit object representation. Every ordinary-pointer result with numeric address zero is the null pointer.

128-bit integers.

The types __int128 and unsigned __int128 are 16-byte, 16-byte-aligned integers. Their little-endian object representation places the low 64-bit word at the lower address. When the calling convention assigns one to a GENERAL-PAIR, the low word occupies the lower-numbered even register and the high word occupies the following odd register. A returned 128-bit integer therefore uses R0 for the low word and R1 for the high word. Its stack slot is 16-byte aligned.

An ordinary 128-bit load or store may use two 64-bit memory operations. The baseline C atomic object set contains the naturally aligned 1-, 2-, 4-, and 8-byte integer and pointer types.

Floating-point profile.

The bedrock-c profile requires the base floating-point extension. Floating-point helpers may replace unavailable operations only when the F0F15 register calling convention remains available.

Long double.

long double is a distinct C type with the IEEE-754 binary64 object representation, 8-byte size, and 8-byte alignment. It uses the floating-point argument class and returns in F0. It therefore has the same call representation as double. In a variadic call it occupies one 16-byte slot containing its 8-byte binary64 representation.

Complex types.

A complex object contains its real component first and its imaginary component second, each using the corresponding real type’s representation. Therefore float _Complex has size 8 and alignment 4, while double _Complex and long double _Complex have size 16 and alignment 8.

Scalable vector and predicate types.

When the scalable-vector extension is present, let \(B\) be VLEN in bytes. A vector object contains exactly \(B\) bytes and has 16-byte alignment. A predicate object contains exactly \(B/8\) packed-image bytes. A private vector spill slot has \(B\) bytes, 16-byte alignment, and \(B\)-byte stride. A private predicate spill slot has 16-byte alignment and \(\operatorname{align\_up}(B/8,16)\)-byte stride. Predicate spill tail padding has unspecified contents. VLEN is stable until reset, so every object and frame in one execution context uses one size.

Aggregate Layout

Aggregate layout applies the scalar and pointer sizes and alignments defined above as follows:

  • Struct fields are laid out in declaration order with natural alignment up to the aggregate maximum.

  • A union’s alignment is the greatest alignment required by any member. Its size is the greatest ABI size of any member, rounded up to a multiple of the union alignment.

  • Arrays store elements contiguously with each element using the ABI size of its type.

  • Aggregate object size is rounded up to the aggregate object’s alignment.

Bit-fields.

A bit-field allocation unit has the size and alignment of its declared base type. Within the little-endian unit, allocation begins at the low bit. A field remains within one allocation-unit boundary, and only consecutive fields whose base types are identical after typedef expansion may share a unit. A base-type change or insufficient remaining space closes the current unit and begins a new naturally aligned unit. A field width is at most the representation width of its base type.

An externally visible bit-field base type shall be _Bool, signed int, unsigned int, or a typedef of one of those types. A plain int bit-field has the value range and representation of signed int. The baseline ABI does not define an external calling or object-layout contract for bit-fields with any other base type.

An unnamed nonzero-width field consumes space normally. A zero-width field closes the current unit and advances layout to the next boundary for its base type while contributing zero storage bytes. Ordinary aggregate alignment, tail-padding, and size-rounding rules still apply after bit-field allocation.

Flexible arrays and extension layout facilities.

A flexible array member contributes zero element-storage bytes to sizeof its containing structure. Its offset is aligned for the element type, and that element alignment participates in the structure’s alignment calculation.

The baseline ABI uses the natural aggregate layout above. Packed aggregates, #pragma pack, empty structures, and zero-length arrays have no external calling or object-layout contract in this ABI.