ID Number: Q81540
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: C9203002
SYMPTOMS
The Microsoft C Compiler versions 6.0, 6.0a, and 6.0ax may produce
incorrect code when casting the result of a shift on an unsigned
integer constant into an unsigned long int. This problem occurs
only if the unsigned integer constant is less than 128, and becomes
apparent only when the result of the shift causes bit 15 to be set.
CAUSE
This problem occurs because the compiler treats the value as a
signed integer if it is less than 128. The code generated contains
the assembly instruction cwd (convert signed word to double) for
the cast from an unsigned int to an unsigned long int. When cwd is
executed on a value that has bit 15 set, bits 16 through 31 are set
causing an incorrect result.
RESOLUTION
To work around this problem, use a variable for the left operand of
the left shift instead of a literal value.
STATUS
Microsoft has confirmed this to be a problem in the Microsoft C
versions 6.0, 6.0a, 6.0ax. This problem was corrected in C/C++
version 7.0.
More Information:
The following line from the /Fc listing of the sample code below shows
the incorrectly generated code:
;|*** k=(unsigned long int)(1U<<i);
; Line 15
*** 00003d b8 01 00 mov ax,1
*** 000040 8a 0e 3a 00 mov cl,BYTE PTR _i
*** 000044 d3 e0 shl ax,cl
*** 000046 99 cwd
*** 000047 a3 00 00 mov WORD PTR _k,ax
*** 00004a 89 16 02 00 mov WORD PTR _k+2,dx
The register values after cwd is executed are as follows:
dx:ax = FFFF:8000
The following line, from the /Fc listing of the sample code below,
shows correctly generated code when using a variable instead of a
literal unsigned int:
;|*** k=(unsigned long int)(j<<i);
; Line 11
*** 000019 8a 0e 3a 00 mov cl,BYTE PTR _i
*** 00001d a1 3c 00 mov ax,WORD PTR _j
*** 000020 d3 e0 shl ax,cl
*** 000022 a3 00 00 mov WORD PTR _k,ax
*** 000025 c7 06 02 00 00 00 mov WORD PTR _k+2,0
Note, for unsigned integers that are 128 or greater, the compiler will
generate the correct code. The following sample code demonstrates this
problem.
Sample Code
-----------
/* Compile options needed: none
*/
#include<stdio.h>
int i=15;
unsigned int j=1;
unsigned long int k;
void main(void)
{
k=(unsigned long int)(j<<i); // k=32768
printf("\ttest one : k=%lu\n",k);
k=(unsigned long int)(1U<<i); // k=4294934528
printf("\t two : k=%lu\n",k);
}
Additional reference words: 6.00 6.00a 6.00ax