[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: busybox zcat errors



Richard Hirst <rhirst@linuxcare.com> writes:
> int main()
> {
>         unsigned char buf[4] = { 0xe9, 0x6c, 0xcf, 0x45 };
>         unsigned long crc = 0x169330baL;
> 
>         printf("buf               = %x\n", buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]);
>         printf("crc ^ 0xffffffffL = %lx\n", (crc ^ 0xffffffffL));
>         if ((buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) != (crc ^ 0xffffffffL))
>                 printf("Oops!\n");
> 
>         return 0;
> }

I believe this is a program bug.  This is what happens according
to C integral promotion rules in the expression inside the "if".

1) buf[0], buf[1] etc. are promoted to int, and notice that this is
   a signed int, even though your chars are unsigned.

Quoting from a fairly old reference..
"A char, short int, or int bit field, either signed or unsigned, or an
 object that has enumeration type, can be used in an expression wherever
 an int or unsigned int is permitted. 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 conversion rules are called the
 integral promotions."

That leaves us with an int of value 0xe96ccf45 on the LHS of the "!=".

2) The RHS is evaluated, with the resultant type an unsigned long of
   value 0x00000000e96ccf45.

3) The LHS (a negative int) is promoted to unsigned long so that the LHS
   and RHS of the "!=" have the same type.  This is a two step process,
   first converting to signed long, then to unsigned long.  The int to
   signed long conversion results in a value of 0xffffffffe96ccf45.

"When a signed integer is converted to an unsigned integer of equal or
 greater size, and the signed integer value is nonnegative, its value
 is unchanged. If the signed integer value is negative, then:

    * If the unsigned integer type is larger, the signed integer is
      first promoted to the signed integer that corresponds to the
      unsigned integer; then the value is converted to unsigned by
      adding to it one greater than the largest number that can be
      represented in the unsigned integer type.

    * If the unsigned integer type is equal or smaller than the signed
      integer type, then the value is converted to unsigned by adding
      to it one greater than the largest number that can be represented
      in the unsigned integer type."

You can fix the problem by casting the LHS to unsigned int.

-- 
Alan Modra



Reply to: