C9110004: Bit Fields in a Union Not Stored Correctly in C 6.0

ID Number: Q77822

6.00 6.00a 6.00ax | 6.00 6.00a

MS-DOS | OS/2

buglist6.00 buglist6.00a buglist6.00ax

Summary:

PROBLEM ID: C9110004

SYMPTOMS

In the Microsoft C Compiler versions 6.0, 6.0a, and 6.0ax and in

the Microsoft QuickC Compiler versions 2.5 and 2.51, the addresses

of elements in a union should all be the same; however, in a union

of bit fields, the first bit field has a different address from the

rest of the bit fields. A problem also occurs in the union of a

single bit field with another data type, such as a structure. The

bit field and the structure will not have the same address.

As a result of this incorrect storage, setting the first bit field

of a union of bit fields will not set the other bit fields that

should be in its unit. Similarly, setting any bit field in any unit

but the first will not set the first bit field.

RESOLUTION

To work around this problem, place the bit fields in a structure

instead of a union, or in a structure inside the union. This may be

what was desired in the first place, since multiple bit fields in a

union should all have the same value.

STATUS

Microsoft has confirmed this to be a problem in C versions 6.0,

6.0a, and 6.0ax and in QuickC versions 2.5 and 2.51 (buglist2.50,

buglist2.51). We are researching this problem and will post new

information here as it becomes available.

More Information:

The ANSI standard states:

A member of a structure or union may have any object type. In

addition, a member may be declared to consist of a specified

number of bits.

Therefore, it is legitimate to have one or more bit fields in a union

in C and QuickC. This was not a feature in earlier versions of these

products.

In addition

The size of a union is sufficient to contain the largest of its

members. A pointer to a union object, suitably converted, points

to each of its members (or if a member is a bit field, then to

the unit in which it resides).

Therefore, placing a watch on a bit field in CodeView will give us the

contents of the unit in which the bit field resides and watching the

address of the bit field in CodeView gives us the address of the unit.

Note that this is the only way that we can observe the address of a

bit field, since you cannot use the address-of operator on a bit field

in C.

The following examples illustrate the two situations described in the

SYMPTOMS section of the summary and how to work around them. As

indicated before, CodeView must be used to obtain the address of the

unit that a bit field resides in.

Sample Code 1

-------------

/* Compile options needed: none

*/

/*********************************************************************

To see that the address of the 1st bit field incorrectly differs, watch

&avar.x0 (This one differs)

&avar.x1

&avar.x2

.

.

&avar.x6

&avar.x7

Notice that setting avar.x2 to 1 sets all bit fields but avar.x0 to 1.

They should all be set since they are in a union.

To work around the problem, place the bit fields inside of a structure

inside of the union as y0 - y7 are in sample code 2.

*********************************************************************/

typedef union aa

{

unsigned x0:1;

unsigned x1:1;

unsigned x2:1;

unsigned x3:1;

unsigned x4:1;

unsigned x5:1;

unsigned x6:1;

unsigned x7:1;

}a;

a avar;

void main( )

{

avar.x2 = 1;

}

Sample Code 2

-------------

/* Compile options needed: none

*/

/*********************************************************************

To see that the address of the bit field incorrectly differs, watch

&bvar.one.y0

&bvar.one.y1

.

.

&bvar.one.y7

&bvar.byte (This one differs)

(Note that it is not necessary that the fields inside of the structure

be bit fields for this to happen).

Note that setting bvar.y2 to 1 sets all bit fields to 4. This is

because they are all in a single unit, bit 2 is set (2 raised to the

power of 2 is 4), and they are in a structure rather than a union

(unlike sample code 1). However, since the address of bvar.byte

differs, it will be unaffected.

To work around the problem, place

unsigned byte:8;

inside a structure, as y0 - y7 are.

*********************************************************************/

typedef union bb

{

struct

{

unsigned y0:1;

unsigned y1:1;

unsigned y2:1;

unsigned y3:1;

unsigned y4:1;

unsigned y5:1;

unsigned y6:1;

unsigned y7:1;

}one;

unsigned byte:8;

}b;

b bvar;

void main( )

{

bvar.one.y2 = 1;

}

Additional reference words: 6.00 6.00a 6.00ax 2.50 bitfield