We found some stra开发者_运维知识库nge values being produced, a small test case is below. This prints "FFFFFFFFF9A64C2A" . Meaning the unsigned long long seems to have been sign extended. But why ? All the types below are unsigned, so what's doing the sign extension ? The expected output would be "F9A64C2A".
#include <stdio.h>
int main(int argc,char *argv[])
{
unsigned char a[] = {42,76,166,249};
unsigned long long ts;
ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U;
printf("%llX\n",ts);
return 0;
}
In the expression a[3] << 24U
, the a[1]
has type unsigned char
. Now, the "integer promotion" converts it to int
because:
The following may be used in an expression wherever an
int
orunsigned int
may be used:[...]
If an
int
can represent all values of the original type, the value is converted to anint
; otherwise, it is converted to anunsigned int
.
((draft) ISO/IEC 9899:1999, 6.3.1.1 2)
Please note also that the shift operators (other than most other operators) do not do the "usual arithmetic conversions" converting both operands to a common type. But
The type of the result is that of the promoted left operand.
(6.5.7 3)
On a 32 bit platform, 249 << 24 = 4177526784
interpreted as an int
has its sign bit set.
Just changing to
ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24;
fixes the issue (The suffix U
for the constants has no impact).
ts = ((unsigned long long)a[0]) | ((unsigned long long)a[1] << 8U) | ((unsigned long long)a[2] << 16U) | ((unsigned long long)a[3] << 24U);
Casting prevents converting intermediate results to default int type.
Some of the shifted a[i], when automatically converted from unsigned char
to int
, produce sign-extended values.
This is in accord with section 6.3.1 Arithmetic operands, subsection 6.3.1.1 Boolean, characters, and integers, of C draft standard N1570, which reads, in part, "2. The following may be used in an expression wherever an int or unsigned int may be used: ... — An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int. ... If an int can represent all values of the original type ..., the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. ... 3. The integer promotions preserve value including sign."
See eg www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf
You could use code like the following, which works ok:
int i;
for (i=3, ts=0; i>=0; --i) ts = (ts<<8) | a[i];
精彩评论