Aligning Structures between Architectures [ HP C Programmer's Guide ] MPE/iX 5.0 Documentation
HP C Programmer's Guide
Aligning Structures between Architectures
Differences in data type alignment can cause problems when porting code
or data between systems that have different alignment schemes. For
example, if you write a C program on the Series 300/400 that writes
records to a file, then read the file using the same program on a Series
700/800, it may not work properly because the data may fall on different
byte boundaries within the file because of alignment differences.
Three methods can be used for aligning data within structures so that it
can be shared between different architectures.
* Use only ASCII formatted data. This is the safest method, but has
negative performance and space implications.
* Use the HP_ALIGN pragma, which is available on most HP-UX HP C
compilers. It forces a particular alignment scheme, regardless of
the architecture on which it is used. See "The HP_ALIGN pragma"
section for a detailed description of this pragma.
* Define platform independent data structures using explicit
padding.
To illustrate the portability problem raised by different alignments,
consider the following example.
#include <stdio.h>
struct char_int
{
char field1;
int field2;
};
main (void)
{
FILE *fp;
struct char_int s;
:
fp = fopen("myfile", "w");
fwrite(&s, sizeof(s), 1, fp);
:
}
The alignment for the struct that is written to myfile in the above
example is shown in the following diagram.
Figure 2-7. Comparison of HPUX_WORD and HPUX_NATURAL Byte Alignments
In the HPUX_WORD alignment mode, six bytes are written to myfile. The
integer field2 begins on the third byte. In the HPUX_NATURAL alignment
mode, eight bytes are written to myfile. The integer field2 begins on
the fifth byte.
Declaring the HP_ALIGN Pragma
The HP_ALIGN pragma controls data storage allocation and alignment of
structures, unions, and type definitions, using typedefs. It enables you
to control the alignment mode when allocating storage space for data. It
is especially important when used to control the allocation of binary
data that is transmitted among machines having different hardware
architectures.
The HP_ALIGN pragma takes a parameter indicating which alignment mode to
use. Not all modes are available on all HP platforms; the NATURAL
alignment mode is the most widely available on HP-UX. This mode is the
recommended standard.
The syntax for the HP_ALIGN pragma is:
#pragma HP_ALIGN align_mode [PUSH]
#pragma HP_ALIGN POP
where align_mode is one of the following:
HPUX_WORD This is the Series 300/400 alignment mode.
HPUX_NATURAL_S500 This is the Series 500 alignment mode.
HPUX_NATURAL This is the Series 700/800 alignment mode. (The
default mode for HP 9000 Series 700/800 and HP 3000
Series 900 systems.)
NATURAL This mode provides a consistent alignment scheme
across HP architectures.
DOMAIN_WORD This is the word alignment mode on HP Apollo
architecture.
DOMAIN_NATURAL This is the natural alignment mode on HP Apollo
architecture.
MPE_16 This is the HP 3000 Series 4x/5x/6x/7x (MPE V)
alignment mode, and is only available on MPE/iX
systems.
NOPADDING This causes all structures and union members that
are not bit-fields to be packed on a byte boundary.
It does not cause compressed packing where there are
zero bits of padding. It only insures that there
will be no full bytes of padding in the structure or
union.
NOTE The above alignment modes are only available on HP-UX systems, with
the exception of the MPE_16 alignment mode, which is only available
on MPE/iX.
If the optional parameter PUSH is used with an align_mode argument, the
current alignment mode is saved (on an alignment mode stack) and the
specified align_mode becomes the new alignment mode.
The #pragma HP_ALIGN POP restores the alignment mode last pushed on the
alignment mode stack. If the alignment mode stack is empty, the compiler
makes the default alignment the current alignment.
The HP_ALIGN pragma affects struct and union definitions as well as
typedef declarations. It causes data objects that are later declared
using these types to have the size and alignment as specified by the
pragma.
The alignment pragma in effect at the time of data type declaration has
significance. The alignment pragma in effect at the time of data type
declaration has precedence over the alignment pragma in effect when space
for a data object of the previously declared type is allocated.
Using the HP_ALIGN Pragma.
The HP_ALIGN pragma must have a global scope; it must be outside of any
function or enclosing structure or union. For example, suppose you have
the following sequence of pragmas:
#pragma HP_ALIGN HPUX_WORD PUSH
struct string_1 {
char *c_string;
int counter;
};
#pragma HP_ALIGN HPUX_NATURAL PUSH
struct car {
long double car_speed;
char *car_type;
};
#pragma HP_ALIGN POP
struct bus {
int bus_number;
char bus_color;
};
#pragma HP_ALIGN POP
Variables declared of type struct string_1, are aligned according to the
HPUX_WORD alignment mode. Variables declared of type struct car, are
aligned according to the HPUX_NATURAL alignment mode. Variables declared
of type struct bus are aligned according to HPUX_WORD.
Accessing Non-Natively Aligned Data with Pointers.
Be careful when using pointers to access non-natively aligned data types
within structures and unions. Alignment information is significant, as
pointers may be dereferenced with either 8-bit, 16-bit, or 32-bit machine
instructions. Dereferencing a pointer with an incompatible machine
instruction usually results in a run-time error.
HP C permanently changes the size and alignment information of typedefs
defined within the scope of an HP_ALIGN pragma. It makes data objects,
such as pointers, declared by using typedefs, compatible with similar
objects defined within the scope of the pragma.
For example, a pointer to an integer type declared with a typedef that is
affected by the HP_ALIGN pragma will be dereferenced safely when it
points to an integer object whose alignment is the same as that specified
in the pragma.
The typedef alignment information is persistent outside the scope of the
HP_ALIGN pragma. An object declared with a typedef will have the same
storage and alignment as all other objects declared with the same
typedef, regardless of the location of other HP_ALIGN pragma statements
in the program.
There is a slight performance penalty for using non-native data
alignments. The compiler generates slower but safe code for
dereferencing non-natively aligned data. It generates more efficient
code for natively aligned data.
The following program generates a run-time error because a pointer that
expects word-aligned data is used to access a half-word aligned item:
#pragma HP_ALIGN HPUX_WORD
struct t1 { char a; int b;} non_native_rec;
#pragma HP_ALIGN POP
main ()
{
int i;
int *p = &non_native_rec.b;
i = *p; /* assignment causes run-time bus error */
}
The following program works as expected because the pointer has the same
alignment as the structure:
#pragma HP_ALIGN HPUX_WORD
struct t1 { char a; int b;} non_native_rec;
typedef int non_native_int;
#pragma HP_ALIGN POP
main ()
{
int i;
non_native_int *p = &non_native_rec.b;
i = *p;
}
An alternative to using the HP_ALIGN pragma and typedefs to control
non-natively aligned pointers is to use the +ubytes compiler option of HP
C/HP-UX. The +ubytes forces all pointer dereferences to assume that data
is aligned on 8-bit, 16-bit, or 32-bit addresses. The value of bytes can
be 1 (8-bit), 2 (16-bit), or 4 (32-bit). This option can be used when
accessing non-natively aligned data with pointers that would otherwise be
natively aligned. This option can be useful with code that generates the
compiler warning message:
#565 - "address operator applied to non natively aligned member."
and aborts with a run-time error.
The +ubytes option affects all pointer dereferences within the source
file. It can have a noticeable, negative impact on performance.
NOTE The HP C/iX implementation of the +u option omits the bytes
parameter. Specifying this option on MPE/iX forces all pointers to
be accessed with 16-bit addressing.
Defining Platform Independent Data Structures
One way to avoid trouble caused by differences in data alignment is to
define structures so they are aligned the same on different systems. To
do this, use padding bytes--that is, dummy variables to align fields the
same way on different architectures.
For example, use:
struct {
char cl;
char dum1;
char dum2;
char dum3;
int i1;
};
instead of:
struct {
char c1;
int i1;
};
MPE/iX 5.0 Documentation