8

Suppose the following:

unsigned char foo = 3;
unsigned char bar = 5;

unsigned int shmoo = foo + bar;

Are foo and bar values guaranteed to be promoted to int values for the evaluation of the expression foo + bar -- or are implementations allowed to promote them to unsigned int?

In section 6.2.5 paragraph 8:

For any two integer types with the same signedness and different integer conversion rank (see 6.3.1.1), the range of values of the type with smaller integer conversion rank is a subrange of the values of the other type.

In section 6.2.5 paragraph 9:

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.

The guarantee that an integer type with smaller integer conversion rank has a range of values that is a subrange of the values of the other type seems dependent on the signedness of the integer type.

  • signed char corresponds to signed int
  • unsigned char corresponds to unsigned int

Does this mean that the value of an unsigned char is only guaranteed to be in the subrange of unsigned int and not necessarily int? If so, does that imply that an implementation could theoretically have an unsigned char value which is not in the subrange of an int?

Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • [Deep C: Integer Promotion](http://www.idryman.org/blog/2012/11/21/integer-promotion/) – Grijesh Chauhan Jul 26 '13 at 13:17
  • Unless you find a system where int is 8 bits it should work as section 6.2.5 paragraph 9 points out. – hetepeperfan Jul 26 '13 at 13:21
  • @GrijeshChauhan I think that website is assuming the minimum magnitudes for the integer types. I believe implementations are only required to support these minimum magnitudes, but are allowed to define the range magnitudes to be greater (section 5.2.4.2.1: `Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.`). – Vilhelm Gray Jul 26 '13 at 13:24
  • @VilhelmGray I just asked because it seems you are posting related questions,.. Well @ Ouah is helping you so, good luck! – Grijesh Chauhan Jul 26 '13 at 13:27
  • 2
    @hetepeperfan In a standard C compiler, `int` has to be at least 16 bits, but nothing prevents `unsigned char` to be as wide as `int` (for instance both 24-bit) in which case `unsigned char` would promote to `unsigned int`. – Pascal Cuoq Jul 26 '13 at 13:28
  • Read this too: http://stackoverflow.com/questions/17869967/unsigned-char-c-255-is-11111111-or-not – Grijesh Chauhan Jul 26 '13 at 13:29
  • @PascalCuoq Good point, I mistakenly assumed (unsigned) char to be 8 bits. – hetepeperfan Jul 26 '13 at 13:32

2 Answers2

8

are implementations allowed to promote them to unsigned int?

Implementations will promote to unsigned int if not all unsigned char values are representable in an int (as ruled by 6.2.5p9 in C99). See below for implementation examples.

If so, does that imply that an implementation could theoretically have an unsigned char value which is not in the subrange of an int?

Yes, example: DSP cpu with CHAR_BIT 16 or 32.

For example, TI C compiler for TMS320C55x: CHAR_BIT is 16 and UCHAR_MAX 65535, UINT_MAX 65535 but INT_MAX 32767.

http://focus.ti.com/lit/ug/spru281f/spru281f.pdf

ouah
  • 142,963
  • 15
  • 272
  • 331
  • I believe this possibility is the reason that it must be possible for `char` to be signed (since all values of `char` must fit within `int`). Conversely, the requirement that all members of the C character set forces some compilers to have `char` be unsigned (e.g. in EBCDIC I think the digits 0-9 are 0xF0-0xF9). – supercat Aug 26 '13 at 19:08
  • If I have something like this `int x = 1234` and `char *y = &x` . Binary representation of `1234 ` is `00000000 00000000 00000100 11010010` . My machine is little endian so it reverses it and store in memory `11010010 00000100 00000000 00000000` LSB comes first. Now Main Part . if i use `printf("%d" , *p)`. `printf` will read first byte `11010010`only the output is `-46` but `11010010` is `210` so why does it print `-46` . I am really confused i guess some char to integer promotion is doing something but i don't know. – Suraj Jain Aug 17 '16 at 10:25
  • @SurajJain I think you mean `printf("%d" , *y)`. `d` specifier writes a signed value and `11010010` is `-46` in two's complement representation. Use `printf("%d" , (unsigned char) *y)` to write the unsigned value. If you have more questions, can I suggest to open a stackoverflow question? – ouah Aug 17 '16 at 15:59
  • Sir , i opened a Question And When i founded answer i wrote it , i wanted it to get checked since months , can you please do it for me , i just wanted to confirm that what i wrote was correct and would not lead anyone in wrong direction. http://stackoverflow.com/questions/34826036/confused-about-pointer-dereferencing – Suraj Jain Dec 27 '16 at 16:04
  • @SurajJain comment added. – ouah Dec 28 '16 at 11:39
  • Does using %d for printing char defined? John Bode Says It is not. – Suraj Jain Dec 28 '16 at 11:41
  • @SurajJain "%d" expects to match an `int` argument. `char` are passed to `...` functions as `int` or rarely `unsigned`. When passed as `unsigned` and still in range of `[0...INT_MAX]` all is well. Else UB. – chux - Reinstate Monica Jan 03 '17 at 16:09
0

I ran across this yesterday - hope that my answer is on topic.

uint8_t x =  10;
uint8_t y = 250;

if (x - y > 0) {
    // never happens
}

if (x - y < 0U) {
    // always happens
}

To my eyes at least it was appearing as though values x and y were being unexpectedly promoted, when in fact is was their result that was promoted.

natersoz
  • 1,674
  • 2
  • 19
  • 29
  • I don't understand what you're saying. x and y are both supposed to be promoted to int so you should have -240 which is then promoted to unsigned for the comparison (4294967056 < 0U) which should never happen. – newguy Nov 25 '16 at 04:48