On Sat, Apr 27, 2013 at 08:55:35PM -0300, Luiz Angelo Daros de Luca wrote:
> I was curious about the "undefined". I found the text:
> 
>    The integer promotions are performed on each of the operands. The
>    type of the result is that of the promoted left operand. If the
>    value of the right operand is negative or is greater than or
>    equal to the width of the promoted left operand, the behavior is
>    undefined.

Actually this part is not the problem here - the unsigned char
argument will be promoted to int before the shift operation, and the
width of int is 32 on all platforms currently supported by mainline
Linux, therefore left shift by 24 bits is allowed.  The problem is the
next paragraph:

   The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated
   bits are filled with zeros. If E1 has an unsigned type, the value
   of the result is E1 * 2^E2 , reduced modulo one more than the
   maximum value representable in the result type. If E1 has a signed
   type and nonnegative value, and E1 * 2^E2 is representable in the
   result type, then that is the resulting value; otherwise, the
   behavior is undefined.

Therefore (0x80 << 24) is undefined, because 0x80000000 is not
representable as a 32-bit signed int.  Apparently the intent here is
to outlaw any form of signed integer overflow (note that the behavior
of right shifts applied to negative signed integer values is not
"undefined", but "implementation-defined" - probably because this
operation does not involve overflow).

Note that the older C89 standard did not declare such left shift
operations as undefined.

GCC 4.8.0 documentation says that it currently does not treat
overflowing left shifts of signed values as undefined:

  http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Integers-implementation.html

However, some prerelease versions of gcc-4.8.0 had a bug related to
such shift operations, which was fixed before the 4.8.0 release:

  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54027

In particular, the comment 2 there says that the intent of GCC
developers is to keep such shifts working.

> So, as left operand is 8bit, the right operant must not be over 8. Does a
> simple typecast solves it?
> 
> return (u32)((u32)p[0] | (u32)p[1] << 8 | (u32)p[2] << 16 | (u32)p[3] <<
> 24);

The outer typecast is not required at all (it will be performed during
return anyway), and the only really required typecast according to the
standard is the last one (other operations can be performed with
signed int values, and the "usual arithmetic conversions" of signed
int and unsigned int will result in unsigned int).

Attachment: signature.asc
Description: Digital signature

_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to