Derived Types
Overview
A type is said to be derived if it is defined relative to other types. Pointers are examples of derived types.
Aggregate Data Types
The aggregate data types are so called because they combine multiple instances of one or several other data types.
Arrays
An array is a contiguous sequence of objects. A fixed-length array (FLA) has a predetermined size. Their stack allocations can be computed at compilation time. A variable-length array (VLA) has its size determined at runtime. Their stack allocations must be determined with respect to other registers available to the frame.
Evaluation of an array A returns &A[0], i.e. a pointer to the first array element. This is called array-to-pointer decay (or just array decay).
Structure
A structure is used to combine multiple objects of potentially different data types together into a single construct. Except for VLAs, any data type is allowed to be a struct member.
The offset of a member can be found using the offsetof macro provided by <stddef.h>.
As a special case, the last member of a structure with more than one named member may have an incomplete array type. This is called a flexible array member. Accessing the member behaves as if that member were replaced with the longest array that would not make the structure larger than the object being accessed.
Stride Address
A struct's stride address refers to the first address following the struct data that has the same alignment as the struct. In general the compiler adds various constraints to how a struct is layed out:
- The
struct's alignment follows that of its widest scalar member.- This guarantees each member satisfies its own self-alignment requirement.
- The
structintroduces trailing padding up to its stride address.- This ensures each element in an array satsifies its self-alignment requirement.
Unions
A union is a grouping of data together but with overlaid storage. It is especially useful for type punning.
Bit-Fields
A member of a structure or union may be declared to consist of a specified number of bits (including a sign bit, if any). Such a member is called a bit-field; its width is preceded by a colon. Its width must be an ICE with a nonnegative value that fits within the specified type. For example:
struct Example {
bool a : 1;
signed int b : 4;
unsigned int c : 4;
signed _BitInt(N) : N;
unsigned _BitInt)(N) : N;
}
A bit-field type is a qualified or unqualified version of bool, signed int, unsigned int, a bit-precise integer, or some other implementation-defined type. Unlike elsewhere, a bit-field with type int may be signed or unsigned.
An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined.
A bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed.