HPlogo HP C/HP-UX Programmer's Guide: HP 9000 Computers > Chapter 2 Storage and Alignment Comparisons

Data Type Size and Alignments

» 

Technical documentation

Complete book in PDF

 » Table of Contents

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.

The Purpose of Alignment Modes

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

ArchitectureDefault Alignment Mode
Series 300/400HPUX_WORD
Series 500HPUX_NATURAL_S500
HP 9000 Workstations and Servers, and HP 3000 Series 900HPUX_NATURAL
Consistent across architecturesNATURAL
HP ApolloDOMAIN_WORD
HP Apollo natural alignmentDOMAIN_NATURAL

 

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.

Alignment Rules

This discussion of alignment rules divides them into sections on scalar types, arrays, structures and unions, bit-fields, and typedefs.

NOTE: In the discussion that follows, the data type size and alignments shown are for both the 32-bit data model (ILP32) and the 64-bit data model (LP64). In cases where there is a difference in data type size or alignment between these two data models, the 64-bit value is shown in parenthesis.

Alignment of Scalar Types

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.

NOTE: Except for the HPUX_NATURAL and DOMAIN_NATURAL modes, the alignment of scalar types inside a structure or union may differ. (See the next sesction“Alignment of Structures and Unions”.) Also, a type that is defined via a typedef to any of the scalar types described may have a different alignment (see “Alignment of Typedefs ”.)

Alignment of Arrays

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:

int arr[100];

The size of the array element type is 4 bytes and the number of elements is 100.

Alignment of Structures and Unions

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.

NOTE: These rules are not true if the member type has been previously declared under another alignment mode. The member type will retain its original alignment, overriding other modes in effect. See “Using the HP_ALIGN Pragma” for information on controlling alignment of structures and unions.

Table 2-2 “Byte Alignment of Structure or Union Members” lists the alignments for structure and union members.

Table 2-2 Byte Alignment of Structure or Union Members

Data Type

HPUX_
WORD DOMAIN_WORD

HPUX_
NATURAL DOMAIN_
NATURAL

HPUX_ NATURAL_
S500

NATURAL

NOPADDING

char, signed char, unsigned char, char enum
(1 byte)

1

1

1

1

1

short, unsigned short, signed short, short enum
(2 bytes)

2

2

2

2

1

int, signed int, unsigned int, int enum
(4 bytes)

2

4

4

4

1

long, signed long, unsigned long, long enum
(4 bytes)
(LP64=8)

2

4
(LP64=8)

4

4
(LP64=8)

1

enum
(4 bytes)

2

4

4

4

1

long long
(8 bytes)

2

8

4

8

1

pointer
(4 bytes)
(LP64=8)

2

4
(LP64=8)

4

4
(LP64=8)

1

long pointer
(8 bytes)

2

4
(LP64=8)

4

4
(LP64=8)

1

float
(4 bytes)

2

4

4

4

1

double
(8 bytes)

2

8

4

8

1

long double
(16 bytes)

2

8
(LP64=16)[1]

4

8
(LP64=16)

1

arrays

Follows alignment of array type inside a structure or union.

struct, union

Follows alignment of its most restricted member, or any minimum alignment.

[1] Only in HPUX_NATURAL—not in DOMAIN_NATURAL.

 

HPUX_WORD/DOMAIN_WORD Alignments

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:

     struct st {
char c;
long l;
char d;
short b;
int i[2];
} s;

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.

       Identifier         Class       Type              Address
- - -
s ext def struct st
c member char 0x0 @ 0x0
l member long int 0x2 @ 0x0
d member char 0x6 @ 0x0
b member short int 0x8 @ 0x0
i member ints [2] 0xa @ 0x0

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.)

Figure 2-1 Example of HPUX_WORD/DOMAIN_WORD Alignment for Structure s in 32-bit Mode

Example of HPUX_WORD/DOMAIN_WORD Alignment for Structure s in 32-bit Mode
HPUX_NATURAL/DOMAIN_NATURAL Alignments

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:

       Identifier         Class       Type              Address
- -
s ext def struct st
c member char 0x0 @ 0x0
l member long int 0x4 @ 0x0
d member char 0x8 @ 0x0
b member short int 0xa @ 0x0
i member ints [2] 0xc @ 0x0

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 ”.

Figure 2-2 Example of HPUX_NATURAL/DOMAIN_NATURAL Alignment for Structure s

Example of HPUX_NATURAL/DOMAIN_NATURAL Alignment for Structure s
HPUX_NATURAL_S500 Alignments

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:

     struct {
char c;
double d;
} s1;

compiled with the +m option produces:

       Identifier         Class       Type              Address
- - -
s1 ext def struct
c member char 0x0 @ 0x0
d member double 0x4 @ 0x0

The entire structure is 4-byte aligned, with a resulting size of 12 bytes.

NATURAL Alignments

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.

NOPADDING Alignments

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:

     #pragma HP_ALIGN NOPADDING
typedef struct s {
char c;
short s;
} s1;

s1 arr[4];

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 ”).

Figure 2-3 Example of NOPADDING Alignment for Structure s1

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.

Alignment of Bit-Fields

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

 Bit-field AlignmentAggregate AlignmentAggregate Size[1]
Modesstructunionstructunionstructunion
HPUX_WORDT < 32 bits: A[2]
T is 32+ bits: B[3]



N/A
T < 32 bits: T
T is 32+ bits: 2
222
HPUX_NATURAL_ S500ATTgreater of 2 and Tgreater of 2 and T
HPUX_NATURALATTTT
NATURALB2222
DOMAIN_ NATURALB2222
DOMAIN_WORDB2222
NOPADDINGB12 (ILP32)
1 (LP64)
12 (ILP32)
1 (LP64)

[1] Aggregate Size refers to the size of a struct or union containing just a one-bit bit-field of type T, where T refers either to the base type of the bit-field, or to that type's size in bits (for example, T is char, size 8, for "char a:1;").

[2] Bit-field alignment A means:

  • If the bit-field has zero length, or if it will cross the next "natural" boundary, it must begin at the next "natural" boundary. The "natural" boundary is the next x-byte boundary, where x is the size, in bytes, of type T.

  • If the bit-field is not of zero length, and it will not cross the next "natural" boundary, the bit-field begins at the current location.

[3] Bit-field alignment B means:

  • If the bit-field has zero length, or if it will cross two 2-byte boundaries, it must begin at the next 2-byte boundary.

  • If the bit-field is not of zero length, and it will not cross two 2-byte boundaries, the bit-field begins at the current location.

    The default alignment is HPUX_NATURAL, which uses alignment A

 

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.

Bit-field Alignment Groups

The alignment modes for bit-fields may be grouped as follows:

  • HPUX_NATURAL/HPUX_NATURAL_S500

  • DOMAIN_WORD/DOMAIN_NATURAL/NATURAL/NOPADDING

  • HPUX_WORD (combination of the previous two)

These bit-field alignment groups are discussed below, and examples are provided of each.

HPUX_NATURAL/HPUX_NATURAL_S500 Alignments

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:

      struct {
int a:5;
int b:15;
int c:17;
char :0;
char d:5;
char e:5;
} foo;

when compiled with the +m option produces:

       Identifier           Class       Type              Address
- -
foo ext def struct
a member int 0x0 @ 0x0
b member int 0x0 @ 0x5
c member int 0x4 @ 0x0
<NULL_SYMBOL> member char 0x7 @ 0x0
d member char 0x7 @ 0x0
e member char 0x8 @ 0x0

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 ”.

Figure 2-4 Example of HPUX_NATURAL/HPUX_NATURAL_S500 Alignment for Structure foo

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.

DOMAIN_WORD/DOMAIN_NATURAL/NATURAL and NOPADDING Alignments

For DOMAIN_WORD, DOMAIN_NATURAL, NATURAL, and NOPADDING alignments:

  • All integral types are treated identically; that is, the packing for char a:17 (this is legal) is the same as for int a:17.

  • Bit-fields can cross "natural" boundaries, unlike for HPUX_NATURAL. That is, for int a:30; int b:7;, b will start at bit 30.

  • No bit-field can cross more than one 2-byte boundary. Thus, for int a:14; int b:18;, b will start at bit 16. If it started at bit 14, it would illegally cross both the 2- and 4-byte boundaries.

  • The use of any type and size of bit-field alone will cause the entire structure to have 2-byte alignment (1-byte for NOPADDING).

NOPADDING of bit-fields follows the DOMAIN alignment scheme. This may result in a full byte of padding between two bit-fields.

For example:

     struct {
char c;
int i:31; <-- At offset 2 bytes.
} bar;

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 ”.)

Figure 2-5 Example of NATURAL Alignment for Structure bar

Example of NATURAL Alignment for Structure bar
HPUX_WORD Alignments

For HPUX_WORD alignments:

  • Alignment for char and short bit-fields is identical to that of HPUX_NATURAL.

  • Alignment for any other bit-fields (int, long long, enum, for example) is identical to DOMAIN bit-field alignment.

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:

     #pragma HP_ALIGN HPUX_WORD

char enum b {a};
struct s {
int int_bit :30;
char char_bit :5;
};
struct t {
int int_bit :30;
char enum b char_enum_bit: 5;
};

int main()
{
struct s basic_str;
struct t enum_str;
}

Compilation with the +m option gives the following map:

       Identifier           Class       Type              Address
- -
basic_str auto struct s SP-48
int_bit member int 0x0 @ 0x0
char_bit member char 0x4 @ 0x0
enum_str auto struct t SP-42
int_bit member int 0x0 @ 0x0
char_enum_bit member enum 0x3 @ 0x6

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 ”.

Figure 2-6 Example of Structures basic_str and enum_str

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 of Typedefs

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:

  1. Taking the innermost type from which the typedef name is derived (which may be another derived type).

  2. Setting its alignment to what it would be if it were used inside a structure or union declaration.

  3. Creating a derived type from that new type, associating it with the typedef name.

Let us start with a simple example[1] of a declaration under NOPADDING:

       typedef int my_int;

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:

       typedef int **my_double_ptr;

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:

    typedef int *my_ptr;
typedef my_ptr *my_double_ptr;

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:

       #pragma HP_ALIGN NOPADDING

typedef int **my_double_ptr;

struct s {
int **p;
};

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.

Summary of Alignment Modes

Table 2-4 “Alignment Mode Summary” provides a summary of the differences between otherwise similar alignment modes.

Table 2-4 Alignment Mode Summary

General Alignment CategoryModes in CategoryDifferences
1-byteNOPADDINGN/A
2-byteHPUX_WORD
DOMAIN_WORD
Same except for bit field alignment.
4-byteHPUX_NATURAL_S500N/A
"natural"HPUX_NATURAL
NATURAL
DOMAIN_NATURAL
HPUX_NATURAL and NATURAL are the same except for the alignment of bit fields and the minimum alignment of structs and unions.
DOMAIN_NATURAL is like NATURAL except for the alignment of structs and unions, and that the alignment of long doubles in 64-bit mode is 8-byte.

 



[1] the example asumes the ILP32 data model.

© Hewlett-Packard Development Company, L.P.