ID Number: Q67785
6.00 6.00a 6.00ax | 6.00 6.00a
MS-DOS | OS/2
buglist6.00 buglist6.00a buglist6.00ax fixlist7.00
Summary:
SYMPTOMS
In Microsoft C versions 6.0, 6.0a, and 6.0ax, bit manipulations on
type char may produce different results depending on the compiler
switches. The /J and /qc switches have different effects on the
code below when using the Microsoft C Compiler version 6.0, 6.0a,
or 6.0ax.
CAUSE
The differences occur because of a problem in the Quick Compiler.
When an integral promotion is required, the Quick Compiler
incorrectly converts an unsigned char to an unsigned int. According
to ANSI specifications, if all the values of a char can be
represented in an int, it is converted to an int; otherwise, it is
converted to an unsigned int (see Section 3.2.1.1). This is also
documented in the "Microsoft C Advanced Programming Techniques"
manual on page 422.
RESOLUTION
There are a number of ways to work around this problem depending on
the desired results:
- If the intent was to generate results equal to F9F7F8F6 (as the
Quick Compiler with /J did), declare "p" as a pointer to an
unsigned char and modify the equations for "result1" and
"result2" to use unsigned int casts where appropriate. For
example:
result1 = *p | ((unsigned int)*(p+2) << 8);
result1 += ( *(p+1) | ( *(p+3) << 8)) * 0x10000;
-or-
result2 = ((unsigned long)(((unsigned int)*(p+2) << 8) | *p)|
(unsigned long)(( *(p+3) << 8) | *(p+1)) << 16;
- If the results from the full optimizing compiler with /J are
desired, again declare "p" as a pointer to unsigned char and
replace the above mentioned casts with signed int.
- If the results without /J are desired, declare "p" as a pointer
to a signed char.
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:
Sample Code
-----------
#include <stdio.h>
char unsigned ary[4] = {0xF6, 0xF7, 0xF8, 0xF9};
void main(void)
{
unsigned long result1, result2;
char *p;
p = ary;
result1 = *p | ( *(p+2) << 8);
result1 += ( *(p+1) | ( *(p+3) << 8)) * 0x10000;
result2 = (unsigned long)(( *(p+2) << 8) | *p) |
(unsigned long)(( *(p+3) << 8) | *(p+1)) << 16;
printf("result1 = %lX\n", result1);
printf("result2 = %lX\n", result2);
}
More Information:
When compiled with /qc and /J, the results are:
result1 = F9F7F8F6
result2 = F9F7F8F6
When compiled with /J, the results are:
result1 = F9F6F8F6
result2 = FFFFF8F6
When compiled with /qc or no options, the results are:
result1 = FFF6FFF6
result2 = FFFFFFF6
Additional reference words: 6.00 6.00a 6.00ax