PRB: Incorrect Code with Unsigned Chars in Loops

ID Number: Q33368

5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a

MS-DOS | OS/2

buglist5.10 buglist6.00 buglist6.00a buglist6.00ax buglist7.00

Summary:

SYMPTOMS

In Microsoft C versions 5.1, 6.0, 6.0a, 6.0ax, and C/C++ version 7.0,

incorrect code may be generated for arithmetic operations on unsigned

chars that are located inside of loops. This problem may occur when

relaxed alias checking (/Oa) is used with loop optimization (/Ol).

RESOLUTION

Turning off either loop optimization or relaxed alias checking may

alleviate the problem. Also, in the example below, casting TestVar

to an unsigned short in the statement that calculates ProcessVar

may alleviate the problem. Declaring the variables in question to

unsigned short will solve the problem.

STATUS

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

6.0, 6.0a, 6.0ax, and C/C++ version 7.0. We are researching this

problem and will post new information here as it becomes available.

More Information:

The following code should print the remainder multiplied by 10 of

each number entered. However, ProcessVar is erroneously always zero.

Sample Code

-----------

/* Compile options needed:

*/

#include <stdio.h>

#include <stdlib.h>

int main (int argc, char *argv[]);

int main (int argc, char *argv[])

{

unsigned char TestVar;

unsigned char ProcessVar;

int i;

if (argc < 2)

printf("usage: %s <integer 1> <integer 2>...<integer n>\n",argv[0]);

else {

for (i = 1; i < argc; i++) {

TestVar = (unsigned char) atoi (argv[i]);

ProcessVar = (unsigned char) ((TestVar % 10) * 10);

printf("ProcessVar: %d\n", ProcessVar);

}

}

return 0;

}

The incorrect assembly for the arithmetic operation is as follows:

;|*** ProcessVar = (TestVar % 10) * 10;

; Line 19

*** 000045 2a e4 sub ah,ah

*** 000047 8b c2 mov ax,dx

*** 000049 d0 e2 shl dl,1

*** 00004b d0 e2 shl dl,1

*** 00004d 02 d0 add dl,al

*** 00004f d0 e2 shl dl,1

*** 000051 88 56 fe mov BYTE PTR [bp-2],dl

Additional reference words: 5.10 6.00 6.00a 6.00ax 7.00