[comp.sys.hp] Bit field alignment on HP-UX

piet@cs.ruu.nl (Piet van Oostrum) (07/13/90)

I am still trying to get the whole scoop on bit-field alignment in the
HP-UX cc compiler on HP9000/300. I detected another case where the
bit-field was aligned, which is actually more in line with what others do -
if there were not a case that I don't understand -

struct test {
/*    char p;*/
    int a:14;
    int b:20;
    short c:5; } x;

This case (with the char p commented out) aligns b on a 2-byte boundary,
presumably because it would otherwise cross a 4-byte boundary, although
4-byte boundaries are not special in records. But if the char p is
inserted, no padding is done, the field a doesn't even start on a 2-byte
boundary. Now I don't understand what the underlying algorithm is. This
might even be a bug. 
-- 
Piet* van Oostrum, Dept of Computer Science, Utrecht University,
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-531806   Uucp:   uunet!mcsun!ruuinf!piet
Telefax:   +31-30-513791   Internet:  piet@cs.ruu.nl   (*`Pete')

mike@hpfcso.HP.COM (Mike McNelly) (07/17/90)

> / hpfcso:comp.sys.hp / piet@cs.ruu.nl (Piet van Oostrum) /  2:16 am  Jul 13, 1990 /
> I am still trying to get the whole scoop on bit-field alignment in the
> HP-UX cc compiler on HP9000/300. I detected another case where the
> bit-field was aligned, which is actually more in line with what others do -
> if there were not a case that I don't understand -
> 
> struct test {
> /*    char p;*/
    > int a:14;
    > int b:20;
    > short c:5; } x;
> 
> This case (with the char p commented out) aligns b on a 2-byte boundary,
> presumably because it would otherwise cross a 4-byte boundary, although
> 4-byte boundaries are not special in records. But if the char p is
> inserted, no padding is done, the field a doesn't even start on a 2-byte
> boundary. Now I don't understand what the underlying algorithm is. This
> might even be a bug. 
> -- 
> Piet* van Oostrum, Dept of Computer Science, Utrecht University,
> Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
> Telephone: +31-30-531806   Uucp:   uunet!mcsun!ruuinf!piet
> Telefax:   +31-30-513791   Internet:  piet@cs.ruu.nl   (*`Pete')
> ----------

The best and most current source of information about bitfields on
Series 300 is the HP-UX Portability Guide, HP Part Number 98794-90046.
The information below was an original source for that discussion
although I believe that signed bitfields are now supported.

Mike McNelly
mike%hpfcla@hplabs.hp.com
=======================================================================

Bitfields are assigned left to right and are unsigned regardless of the
declared type.  They are aligned so that they do not violate the
alignment restriction of the declared type.  Consequently some padding
within the structure may be required.

For example,

	struct foo
		{
		unsigned int	a:3, b:3, c:3, d:3;
		unsigned int	remainder:20;
		};

For the above struct, sizeof(struct foo) would return 4 (bytes) because
none of bitfields straddle a 4 byte boundary.  On the other hand, the
following struct declaration will have a larger size.

	struct foo2
		{
		unsigned char	a:3, b:3, c:3, d:3;
		unsigned int	remainder:20;
		};

In this struct declaration the assignment of data space for c must be
aligned so as not to violate a byte boundary, which is the normal
alignment of unsigned char.  Consequently two undeclared bits of padding
are added by the compiler so that c is aligned on a byte boundary.
sizeof(struct foo2) therefore returns 6 (bytes).

Bitfields on Series 200, 300, and 500 machines cannot exceed the size of
the declared type in length.  Therefore the largest possible bitfield is
32 bits.  All scalar types are permissable to declare bitfields,
including enums.  However, they are inherently unsigned.

piet@cs.ruu.nl (Piet van Oostrum) (07/18/90)

In article <7370172@hpfcso.HP.COM>, mike@hpfcso (Mike McNelly) writes:
 |
 |The best and most current source of information about bitfields on
 |Series 300 is the HP-UX Portability Guide, HP Part Number 98794-90046.
 |The information below was an original source for that discussion
 |although I believe that signed bitfields are now supported.
 |
 |Mike McNelly
 |mike%hpfcla@hplabs.hp.com
 |=======================================================================
 |
 |Bitfields are assigned left to right and are unsigned regardless of the
 |declared type.  They are aligned so that they do not violate the
 |alignment restriction of the declared type.  Consequently some padding
 |within the structure may be required.
 |
 |For example,
 |
 |	struct foo
 |		{
 |		unsigned int	a:3, b:3, c:3, d:3;
 |		unsigned int	remainder:20;
 |		};
 |
 |For the above struct, sizeof(struct foo) would return 4 (bytes) because
 |none of bitfields straddle a 4 byte boundary.  On the other hand, the
 |following struct declaration will have a larger size.
 |
 |	struct foo2
 |		{
 |		unsigned char	a:3, b:3, c:3, d:3;
 |		unsigned int	remainder:20;
 |		};
 |
 |In this struct declaration the assignment of data space for c must be
 |aligned so as not to violate a byte boundary, which is the normal
 |alignment of unsigned char.  Consequently two undeclared bits of padding
 |are added by the compiler so that c is aligned on a byte boundary.
 |sizeof(struct foo2) therefore returns 6 (bytes).
 |
 |Bitfields on Series 200, 300, and 500 machines cannot exceed the size of
 |the declared type in length.  Therefore the largest possible bitfield is
 |32 bits.  All scalar types are permissable to declare bitfields,
 |including enums.  However, they are inherently unsigned.

I had read this passage several times, and I have tried to attach some kind
of semantics to it. I think the wording is highly ambiguous, but I thik I
have grasped its meaning now. Let me try to formulate the underlying algorithm.

1. A halfword is a sequence of two bytes starting at an even address, a
longword is a sequence of four bytes starting at any EVEN address. (these
are the words as I am going to use them below.

2. A bitfield that is declared as a char must fit into a byte, a field that
is declared as a short must fit into a halfword (as defined above), and a
field that is declared as an int or long must fit into a longword. If the
field does not fit, it is aligned on the next boundary (1 byte for char, 2
bytes for short/int/long).

The following examples illustrate this:

I. struct test {
    int a:14;
    int b:20;
    int c:5; } x;

b will be aligned because otherwise it would occupy (part of) bytes 1,2,3,4,
which is one byte more than the longword starting at byte 0.

II. struct test {
    char p;
    int a:14;
    int b:20;
    int c:5; } x;

Now NO PADDING is required because a fits in the logword starting at byte 0
and b spans byte 2,3,4,5 which fits into the longword starting at byte 2.

III. struct test {
    char p;
    short a:14;
    int b:20;
    int c:5; } x;

In this case a is defined as short so it has to fit into a halfword. It
doesn't fit into the halfword at byte 0, so it is aligned on byte 2.
-- 
Piet* van Oostrum, Dept of Computer Science, Utrecht University,
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-531806   Uucp:   uunet!mcsun!ruuinf!piet
Telefax:   +31-30-513791   Internet:  piet@cs.ruu.nl   (*`Pete')

mike@hpfcso.HP.COM (Mike McNelly) (07/19/90)

Your interpretation is correct.

Mike McNelly
mike%hpfcla@hplabs.hp.com