2

Compiling the following snippet using C++11(demo here):

#include <stdint.h>

int main() {
    const uint8_t foo[] = {
        '\xf2'
    };
}

Will trigger a warning(at least on GCC 4.7), indicating that there's a narrowing conversion when converting '\xf2' to uint8_t.

Why is this? sizeof(char) is always 1, which should be the same as sizeof(uint8_t), shouldn't it?

Note that when using other char literals such as '\x02', there's no warning.

mfontanini
  • 21,410
  • 4
  • 65
  • 73

2 Answers2

6

Although char doesn't necessarily have to be 8-bits long, that's not the problem here. You are converting from signed char to unsigned (uint8_t), that's the reason for the error.

This:

const int8_t foo[] = {
    '\xf2'
};

will compile fine.

David G
  • 94,763
  • 41
  • 167
  • 253
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
  • `\xf2` is 242. That doesn't fit in a signed char, does it? – jrok Mar 31 '13 at 14:17
  • 1
    Now I'm wondering why this: `const uint8_t foo = '\xf2';` doesn't trigger any warnings. – mfontanini Mar 31 '13 at 14:20
  • `\xf2` equals to binary 11110010. This fits into a signed char as -14 – SomeWittyUsername Mar 31 '13 at 14:20
  • `\xf2` has type `int` though. – jrok Mar 31 '13 at 14:21
  • 1
    @jrok Not in C++. In C, it is. In C++, it's `char`. –  Mar 31 '13 at 14:24
  • @icepack But isn't signed integer overflow undefined behavior (or has at least an unspecified reasult)? –  Mar 31 '13 at 14:24
  • @mfontanini That's a good question. There are related questions on SO: http://stackoverflow.com/questions/8251059/c11-variable-narrowing-with-no-gcc-compiler-warning and http://stackoverflow.com/questions/4434140/narrowing-conversions-in-c0x-is-it-just-me-or-does-this-sound-like-a-breakin – SomeWittyUsername Mar 31 '13 at 14:25
  • @H2CO3 I don't see overflow here. `\xf2` is a valid value for signed char, it could've been written as -14, for example. – SomeWittyUsername Mar 31 '13 at 14:27
  • @icepack Since - assuming that `char` is 8 bit long, which it seems to be on OP's platform - `CHAR_MAX` is 127, and `0xf2` is more than 127 (`0x7f`), so there is indeed overflow. –  Mar 31 '13 at 14:29
  • @H2CO3 I'm aware of that, but I thought hex escape sequence is a multichar literal which do have type `int`. I looked in standard, and I see I was wrong, it has type `char` indeed. – jrok Mar 31 '13 at 14:30
  • BTW, your original code compiles without a warning on gcc 4.6.3: http://liveworkspace.org/code/1u38hL$7 – SomeWittyUsername Mar 31 '13 at 14:30
  • @H2CO3 But you're interpreting 0xf2 as unsigned value. I'd say it's compiler job to interpret it as a signed value (it's constant after all) where MSB is the sign, and inject it into the code. – SomeWittyUsername Mar 31 '13 at 14:36
  • @icepack No, not quite. There's an implicit type conversion taking place. –  Mar 31 '13 at 14:37
  • 1
    @icepack: the standard says (2.14.3/4) "The value of a character literal is implementation-defined if it falls outside of the implementation-defined range defined for `char`". Which hex `f2` does, since its meaning in an escape sequence is the *number* 242, not the *bit pattern* `11110010`. So there's no portable way to write a character literal with negative value, the portable way to write this is `const int8_t foo[] = { -14 };` – Steve Jessop Mar 31 '13 at 14:42
3

Looking at my system, the constant \xf2 is overflowing, since it's out of range of a signed char. It's being represented as -14 which is then implicitly converted to an unsigned int, giving a value of 4294967282. That's then narrowed to a char, producing this warning:

warning: narrowing conversion of ‘'\37777777762'’

Using (unsigned char)'\xf2' removes the warning.

teppic
  • 8,039
  • 2
  • 24
  • 37