HP C/HP-UX Programmer's Guide: Workstations and Servers > Chapter 2 Storage and Alignment ComparisonsAlignment Rules |
|
This discussion of alignment rules divides them into sections on scalar types, arrays, structures and unions, bit-fields, and typedefs. Scalar types are integral types, floating types, and pointer types. Alignment of scalar types that are not part of a structure, union, or typedef declaration are not affected by the alignment mode. Therefore, they are aligned the same way in all alignment modes. Table 2-2 Aligning Scalar Types
*8 bytes on DOMAIN
An array is aligned according to its element type. For example, a double array is aligned on an 8-byte boundary; and a float array within a struct is aligned on a 4-byte boundary. Alignment of array elements is not affected by the alignment mode, unless the array itself is a member of a structure or union. An array that is a member of a structure or union is aligned according to the rules for structure or union member alignment (see “Alignment of Structures and Unions” below for more information.) An array's size is computed as: (size of array element type) × (number of elements) For instance, the array declared below is 400 bytes (4 × 100) long:
The size of the array element type is 4 bytes and the number of elements is 100. In a structure, each member is allocated sequentially at the next alignment boundary corresponding to its type. Therefore, the structure might be padded internally if its members' types have different alignment requirements. In a union, all members are allocated starting at the same memory location. Both structures and unions can have padding at the end, in order to make the size a multiple of the alignment.
Table 2-3 “Aligning Structure or Union Members ” lists the alignments for structure and union members. Table 2-3 Aligning Structure or Union Members
For HPUX_WORD and DOMAIN_WORD alignments, all structure and union types are 2-byte aligned. Member types larger than 2 bytes are aligned on a 2-byte boundary. Padding is performed as necessary to reach a resulting structure or union size which is a multiple of 2 bytes. For example:
Compiling with the +m option to show the offsets of the identifiers, you will get the following output. Offsets are given as "byte-offset" @ "bit-offset" in hexadecimal.
The resulting size of the structure is 18 bytes, with the alignment of 2 bytes, as illustrated in Figure 2-1 “Example of HPUX_WORD/DOMAIN_WORD Alignment for Structure s ” For HPUX_NATURAL and DOMAIN_NATURAL alignments, the alignment of structure and union types is the same as the strictest alignment of any member. Therefore, they may be aligned on 1-, 2-, 4-, or 8-byte boundaries. Padding is performed as necessary so that the size of the object is a multiple of the alignment size. For example, the declaration shown in the previous section will now be aligned:
In this case, the size of the structure is 20 bytes, and the entire structure is aligned on a 4-byte boundary since the strictest alignment is 4 (from the int and long types), as illustrated in Figure 2-2 “Example of HPUX_NATURAL/DOMAIN_NATURAL Alignment for Structure s ”. For HPUX_NATURAL_S500 alignments, series 500 computers align structures on 2- or 4-byte boundaries, according to the strictest alignment of its members. As with the other alignment modes, padding is done to a multiple of the alignment size. For example, the following code:
compiled with the +m option produces:
The entire structure is 4-byte aligned, with a resulting size of 12 bytes. For NATURAL alignments, structures and unions are aligned on 2-, 4-, or 8-byte boundaries, according to the strictest alignment of its members. Padding is done to a multiple of the alignment size. For NOPADDING alignments, structure or union members are byte aligned; therefore, struct and union types are byte aligned. This alignment mode does not cause compressed packing where there are zero bits of padding. It only ensures that there will be no full bytes of padding in the structure or union, unless bit-fields are used. There may be bit paddings or even a full byte of padding between members if there are bit-fields. Refer to “Alignment of Bit-Fields ” for more information. Consider the following code fragment:
The size of s1 is 3 bytes, with 1-byte alignment. Therefore, the size of arr is 12 bytes, with 1-byte alignment. There is no padding between the individual array elements; they are all packed on a byte boundary (see Figure 2-3 “Example of NOPADDING Alignment for Structure s1 ”). Note that if a member of a structure or union has been declared previously under a different alignment mode, it will retain its original alignment which may not be byte alignment. The NOPADDING alignment will not override the alignment of the member, so there may be some padding done within the structure, and the structure may be greater than byte aligned. Refer to “Aligning Structures Between Architectures” below for examples on on structure alignment for different systems. The alignment modes for bit-fields are grouped differently than they are for the other types. The three groups are:
For HPUX_NATURAL and HPUX_NATURAL_S500 alignments, no bit-field can cross a "natural" boundary. A bit-field that immediately follows another bit-field is packed into adjacent bits, unless the second bit-field crosses a natural boundary according to its type. For example:
when compiled with the +m option produces:
The size of the structure is 12 bytes, with 4-byte alignment as illustrated in Figure 2-4 “Example of HPUX_NATURAL/HPUX_NATURAL_S500 Alignment for Structure foo ”. Since b (being an int type) does not cross any word boundaries, a and b are adjacent. c starts on the next word because it would cross a word boundary if it started right after b. The zero length bit-field forces no further bit-field to be placed between the previous bit-field, if any, and the next boundary described by the zero-length bit field's type. Thus, if we are at bit 5 and see a zero length bit-field of type int, then the next member will start at the next word boundary (bits 5-31 will be empty). However, if we are at bit 5 and see a zero length bit-field of type char, then the next member will start at least at the next byte (bits 5-7 will be empty), depending on whether the next member can start at a byte-boundary. For DOMAIN_WORD, DOMAIN_NATURAL, NATURAL, and NOPADDING alignments:
For example:
The above structure bar will align the bit-field at offset 2 bytes, so that there is a full byte of padding between c and i, even with NOPADDING alignment mode (see Figure 2-5 “Example of NATURAL Alignment for Structure bar ”.) For HPUX_WORD alignments:
Note that alignment of a char or short bit-field may not be the same as alignment of a char or short enum bit-field under the same circumstances. For example:
Compilation with the +m option gives the following map:
Both structures have a resulting size of 6 bytes, with 2-byte alignment as shown in Figure 2-6 “Example of Structures basic_str and enum_str ”. Notice that char_bit follows the HPUX_NATURAL alignment scheme, but char_enum_bit follows the DOMAIN_WORD alignment scheme, even though the length of their bit-field types are equivalent. Alignment for typedefs is slightly different than alignment for structures. Within a structure, the member itself is affected by the alignment mode. However, with a typedef, the alignment of the type that the typedef name is derived from is affected, not the typedef name itself. The typedef name is then associated with the derived type. When a typedef is seen, a new type is created by:
Let us start with a simple example of a declaration under NOPADDING:
Since an int will be 1-byte aligned inside a structure under NOPADDING, my_int will be 1-byte aligned. Consider a pointer typedef with NOPADDING alignment:
my_double_ptr is derived from an integer type; therefore, a new integer type of 1-byte alignment is created. my_double_ptr is defined to be a 4-byte aligned pointer to another 4-byte aligned pointer which points to a byte-aligned int. Consider another example, this time with HPUX_WORD:
In the first typedef, my_ptr will be a 4-byte aligned pointer to a 2-byte aligned int. The second typedef will create another type for my_ptr which is now 2-byte aligned, since my_double_ptr is derived from my_ptr. So my_double_ptr is a 4-byte aligned pointer to a 2-byte aligned pointer which points to a 2-byte aligned int. Similar declarations inside a structure will not have the same resulting alignment. Consider the following declaration:
In the above example, my_double_ptr is a 4-byte aligned pointer type pointing to another 4-byte aligned pointer which points to a 1-byte aligned int. However, struct s member p is a 1-byte aligned pointer which points to a 4-byte aligned pointer which points to 4-byte aligned int. Inside a structure, the member itself is affected by the alignment mode. However, with a typedef, the typedef name is not directly affected. The innermost type from which the typedef name is derived is affected by the alignment mode. |