C9112005: Incorrect Code Generated If % Used on Char in a Sum

ID Number: Q79152

6.00 6.00a 6.00ax | 6.00 6.00a

MS-DOS | OS/2

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

Summary:

PROBLEM ID: C9112005

SYMPTOMS

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

incorrect code is generated to evaluate an expression when the

expression is a sum that meets the following three criteria:

1. One of the addends is a modulus performed on a global variable of

type char (the char could be local if compiling with /Od).

2. The other addend is the same char variable or an expression

involving that char variable.

3. The sum is cast to a char.

CAUSE

The generated code uses an idiv to perform the modulus operation,

and the quotient is used as the addend rather than the remainder.

RESOLUTION

In the following examples, using the quick compile option, /qc,

causes the correct code to be generated. Also, in the case of the

first example, disabling all optimizations with the /Od switch

allows the correct code to be generated.

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 version 7.0.

More Information:

The following code examples meet the above criteria. In the first

example, the addend is the char variable. In the second example, the

addend is an expression involving the char variable.

Sample Code 1

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

/* Compile options needed: no quick compile

*

* Compiling with /Od or /qc generates correct code

*/

#include <stdio.h>

int result;

char val = 15;

void main( )

{

result = (char)( val + val%16 );

printf( "Result = %d\n", result );

}

The expected output is:

Result = 30

The actual output is:

Result = 15

The following is the incorrectly generated code:

; (int) val%16

mov cl, 16 ; put 16 into cl

mov al, BYTE PTR _val ; put val into al

cbw ; sign extend al into ah

idiv cl ; divide ax by cl

; quotient in al, remainder in ah

; add (int) val

add al, BYTE PTR _val ; Incorrect! We should be adding

; to the remainder since a mod

; was performed.

cbw ; sign extend al into ah

mov WORD PTR _result, ax ; store the result

Sample Code 2

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

/* Compile options needed: no quick compile

*

* Compiling with /qc generates correct code

*/

#include <stdio.h>

int result;

char val = 15;

void main( )

{

result = (char)( (int) val/16 + (int) val%16 );

printf( "Result = %d\n", result );

}

The expected output is:

Result = 15

The actual output is:

Result = 0

The following is the code incorrectly generated for the sum:

; (int) val%16

mov al, BYTE PTR _val ; put val into al

mov cl, 16 ; put 16 into cl

cbw ; sign extend al into ah

idiv cl ; divide ax by cl

; quotient in al, remainder in ah

mov dx, ax ; temporarily store result in dx

; (int) val/16

mov al, BYTE PTR _val ; put val into al

cbw ; sign extend al into ah

idiv cl ; divide ax by cl

; add together and put into result

add al, dl ; Incorrect! Remainder from the

; mod operation is in dh, not dl.

cbw ; sign extend al into ah

mov WORD PTR _result, ax ; store the result

Additional reference words: 6.00 6.00a 6.00ax