|
|
HP C/HP-UX Programmer's Guide: HP 9000 Computers > Chapter 2 Storage and Alignment ComparisonsData Type Size and Alignments |
|
This section discusses storage sizes and alignment modes for the HP 9000 and HP Apollo systems as well as the VAX/VMS C, CCS/1000, and CCS/C 3000. Data alignment refers to the way different data types are stored in system memory. By default, data is aligned to take advantage of the system architecture to produce the fastest code. The alignment boundary is in bytes and must be a power of two: 1, 2, 4, 8, or 16 bytes. Bit-fields and aggregates such as structs may require padding (addition of otherwise meaningless bits) to align on the desired boundaries. The compiler automatically performs the default (or "natural") alignment for the target machine architecture unless this default behavior is overridden with a #pragma instruction to use a different alignment mode. You may choose a different alignment mode for greater portability. Table 2-1 lists the names of the default alignment modes for different HP system architectures. Each architecture has a standard (default) alignment which is the fastest alignment for that architecture. You may, however, choose to use a non-standard alignment for greater portability. Table 2-1 “Default Alignment Modes on HP-UX Architectures” lists the name of the default alignment modes for different HP system architectures. Table 2-1 Default Alignment Modes on HP-UX Architectures
In general, the natural alignment mode works best. If you want to specifically create code compatible with code on one of the architectures listed, you can use the HP_ALIGN pragma and specify it. To create code that aligns consistently across different vendors, use the PACK pragma. 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.
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-2 Byte Alignment of 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 (compilation is for the default 32-bit data model.) 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 in 32-bit Mode”. (To avoid restricting your code to 32- or 64-bit, avoid using the long and pointer types and use long long instead.) In this mode, structs and unions may be aligned on 1-, 2-, 4-, or 8-byte boundaries. Padding is performed as necessary so that the size of the aggregate 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 padding 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 within the structure, and the structure may be greater than byte aligned. Refer to “Aligning Structures Between Architectures” for examples on structure alignment for different systems. This section discusses bit-field alignment and how bit-field alignment affects aggregrate alignment. bit-field alignment refers to the alignment of several consecutive bit-fields. Aggregate alignment refers to the bit-field's effect on the alignment of the enclosing struct or union. Table 2-3 “Byte Alignment of Bit-fields and Aggregates with Bit-fields” summarizes bit-field alignments. Table 2-3 Byte Alignment of Bit-fields and Aggregates with Bit-fields
The biggest difference between ILP32 to LP64 data models for bit-fields is the effect of unnamed bit-fields. In ILP32, unnamed bit-fields have the same effect on the alignment of the aggregate as do any other members. In LP64, unnamed bit-fields do not affect the alignment of the structure or union. In both cases, zero-length bit-fields force the following member to the next natural boundary. The alignment modes for bit-fields may be grouped as follows:
These bit-field alignment groups are discussed below, and examples are provided of each. 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:
NOPADDING of bit-fields follows the DOMAIN alignment scheme. This may result in a full byte of padding between two bit-fields. 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[1] 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. Table 2-4 “Alignment Mode Summary” provides a summary of the differences between otherwise similar alignment modes. Table 2-4 Alignment Mode Summary
|
|