C9201006:Optimizations Cause Bad Code Generation w/ Bit Fields

ID Number: Q80122

6.00 6.00a 6.00ax

MS-DOS

buglist6.00 buglist6.00a buglist6.00ax fixlist7.00

Summary:

PROBLEM ID: C9201006

SYMPTOMS

When using Microsoft C version 6.0, 6.0a, or 6.0ax, incorrect code

may be generated when using the /Oc, /Oe, /Og, /Ol, /Ox or the

default optimization switch when accessing bit fields within

structures.

If a variable defined to be a pointer to a structure is used and

the structure has elements as the sample code below shows, a field

in the target structure will not be assigned the correct value.

Note: This code fails only if compiling under MS-DOS. Correct Code

is generated if compiling under OS/2.

RESOLUTION

There are several workarounds to this problem:

- Compile using any optimization except those listed above.

- Perform a quick compile using the /qc switch.

- If using pointers, use a temporary variable to assign fields from

the target structure to the source structure. For example:

unsigned temp;

temp=src->f;

tgt->x=temp;

STATUS

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

6.0a, and 6.0ax. This problem was corrected in C/C++ version 7.0.

More Information:

Using the sample code below, assigning a field with bit width 1 in

SOURCE to a field in TARGET using pointers to the corresponding

structures generates incorrect code causing an incorrect value to be

assigned to the target element.

The code generated contains a statement that depends upon the AH

register having been set to the value of the source element previous

to this code. However, the assumption is incorrect because the last

statement to set the AH register is in the call to malloc(). This

assumption can be seen as follows:

;|*** tgt->z=src->f;

; Line 29

*** 000027 8b 1e 00 00 mov bx,WORD PTR _tgt

; The following statement makes the incorrect assumption.

*** 00002b 8a c4 mov al,ah

*** 00002d 32 07 xor al,BYTE PTR [bx]

*** 00002f 25 04 00 and ax,4

*** 000032 31 07 xor WORD PTR [bx],ax

Sample Code

-----------

/* Compile options needed: -Zi to view in CodeView */

#include <malloc.h>

typedef struct

{

unsigned a:1;

unsigned b:1;

unsigned c:6;

unsigned d:1;

unsigned e:1;

unsigned f:1;

}SOURCE;

typedef struct

{

unsigned x:1;

unsigned y:1;

unsigned z:1;

}TARGET;

SOURCE *src;

TARGET *tgt;

void main(void)

{

src=malloc(sizeof(SOURCE));

tgt=malloc(sizeof(TARGET));

src->f=1;

tgt->z=src->f;

}

Additional reference words: 6.00ax 6.00a 6.00