13

i am reading a .cpp file containing a unsigned char variable, it's trying the bitwise left shift 16 bits, since an unsigned char is composed of 8 bits, left shift 16 bits will erase all the bits and fill it with eight 0s.

unsigned char byte=0xff; byte << 16;

leomayleomay
  • 553
  • 1
  • 7
  • 16
  • 4
    The value of the expression is not assigned. –  May 25 '12 at 04:45
  • 2
    As written, the compiler will optimize the shift operation away as doing nothing. What was the real code? – Jonathan Leffler May 25 '12 at 04:53
  • 1
    you may want to look at this : http://stackoverflow.com/questions/437470/type-to-use-to-represent-a-byte-in-ansi-c89-90-c – AndersK May 25 '12 at 04:55
  • 1
    All built-in operators work on objects of at least int size (see http://stackoverflow.com/a/5563131/14065). Thus: `sizeof(byte << 16) == sizeof(int)` – Martin York May 25 '12 at 04:57

2 Answers2

18

When you shift a value,

unsigned char x = ...;
int y = x << 16;

The type of x is promoted to int if unsigned char fits in an int (most systems), or to unsigned if unsigned char does not fit in an int (rare1). As long as your int is 25 bits wide or wider, then no data will be discarded2.

Note that this is completely unrelated to the fact that 16 has type int.

/* All three are exactly equivalent */
x << 16;
x << 16u;
x << (unsigned char) 16;

Source: from n1516 (C99 draft):

§6.5.7 paragraph 3: Bitwise Shift Operators

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.

§6.3.1.1 paragraph 2: Boolean, characters, and integers

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.

Footnotes:

1: Some DSP chips as well as certain Cray supercomputers are known to have sizeof(char) == sizeof(int). This simplifies design of the processor's load-store unit at the cost of additional memory consumption.

2: If your left shift is promoted to int and then overflows the int, this is undefined behavior (demons may fly out your nose). By comparison, overflowing an unsigned is always well-defined, so bit shifts should usually be done on unsigned types.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Thanks a lot for the elaborate explanation. Though i am still confused about the memory it may accidentally overwrite after promoting the `unsigned char` to `int` – leomayleomay May 25 '12 at 06:41
  • 1
    @leomayleomay: That's not how it works. If you assign an `int` to an `unsigned char` variable, then the `int` is converted. (This isn't assembly language, after all.) – Dietrich Epp May 25 '12 at 08:44
  • so the bitwise left shift here (16 to the left) will make the variable in question to be 0, right? – leomayleomay May 25 '12 at 09:29
  • If you assign `x = x << 16`, then on most systems, this is the same as `x = 0`. – Dietrich Epp May 25 '12 at 09:37
  • 1
    I find this behavior very surprising. I encountered such a behavior using IAR CSTAT static analysis tool for the following code: unsigned short BE2LE16(unsigned short x) { return ((x<<8) | (x>>8));} and couldn't figure it out until your detailed answer. Thank you and IAR so much! – lkanab Aug 10 '16 at 06:00
1

If char fits inside int, it will be promoted to an int and the result will be as you expect. If that is not the case it is undefined behavior according to the standard, and will probably emit a compile warning. From the standard:

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.

Hampus Nilsson
  • 6,692
  • 1
  • 25
  • 29
  • 1
    It will never cause undefined behavior if `char` cannot fit in `int`, since it must therefore fit inside `unsigned int`, and shifts on `unsigned int` are never undefined. Only shifts on signed integers are undefined, and only if the mathematical result cannot be represented by the type. For example, `1 << 16` is undefined if an `int` is 16 bits. – Dietrich Epp May 25 '12 at 04:49
  • 1
    The integer promotions are indeed performed, which means that the behaviour is only undefined if `unsigned char` is promoted to `int` rather than `unsigned int` and the shift would produce a value that cannot be represented in an `int`. – caf May 25 '12 at 04:50
  • @DietrichEpp: Even `0 << 16` is undefined behaviour if `int` is 16 bits though, because of the constraint noted in this answer. – caf May 25 '12 at 04:52