8

The following code:

unsigned char result;
result = (result << 4 );

Compiled with gcc version 4.6.4 (Debian 4.6.4-2), with the -Wconversion flag results in the warning

warning: conversion to 'unsigned char' from 'int' may alter its value [-Wconversion]

Why is that?

Yordan Pavlov
  • 1,303
  • 2
  • 13
  • 26

3 Answers3

9

Because the standard says so. The operands to binary operators undergo integral promotion, in which anything smaller than an int is promoted to int; the results of the operation have type int as well. And if the original value were, say, 0x12, the results would be 0x120, and assigning this to an unsigned char will cause a change in value. (The assigned value will be 0x20.) Whence the warning.

EDIT:

From the standard (§5.8 Shift operators): " The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand." Unlike other binary operators, there is no effort to find a common type from the two operators: the result type is that of the left operand, period. But integral promotion does still occur: the unsigned char will be promoted to int (or to unsigned int if int has a size of 1).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Am I the only one who is bothered that the warning states "from int to unsigned char"? Doesn't sound like integer promotion, but rather reduction of the numeric literal int to unsigned char. GCC 8.3.0 even designates the numeric literal with the `^` marker, not the `result` variable. – Tammi Feb 09 '21 at 17:27
  • I "broke my legs" over this freaking "usual arithmetic conversions" multiple times by now. Debugging my code for days and hours to finally reveal this standard over and over again.... – ScienceDiscoverer Mar 13 '21 at 08:25
  • I understand that this is doe for optimization (ints operations run faster than char/short ones) but this causes so much inconvenience and ambiguity that I'm not really sure why standard did't acknowledged this. – ScienceDiscoverer Mar 13 '21 at 08:32
2

Because the int value can be larger than can fit in an unsigned char.

Think about what will happen when result is 255 (i.e. 0xff). Shifting it left four bits will make it 4080 (or 0xff0). How will the compiler be able to squeeze that value back into result? It can't, so it simply truncates it to 240 (0xf0). In other words, the value of the integer operation result << 4 may be be altered.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

All arithmetic and logical operators perform the "integral promotions" on their arguments. The integral promotions turn types that are smaller than int (like unsigned char) into int or unsigned int. You'll see the same thing if you replace << with +.

Oh, and the parentheses aren't needed.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Whether that eliminates the warning or not depends on the compiler. Even `result <<= 4` involves a narrowing conversion (and of course, the compiler is free to warn about anything it wants anyway). – James Kanze Jul 05 '13 at 13:24
  • @JamesKanze - yup. Removed. – Pete Becker Jul 05 '13 at 13:25