8

I know this is a simple question but I'm confused. I have a fairly typical gcc warning that's usually easy to fix:
warning: comparison between signed and unsigned integer expressions

Whenever I have a hexadecimal constant with the most significant bit, like 0x80000000L, the compiler interprets it as unsigned. For example compiling this code with -Wextra will cause the warning (gcc 4.4x, 4.5x):

int main()
{
long test = 1;
long *p = &test;
if(*p != 0x80000000L) printf("test");
}

I've specifically suffixed the constant as long, so why is this happening?

jww
  • 97,681
  • 90
  • 411
  • 885
test
  • 411
  • 1
  • 4
  • 10
  • 3
    possible duplicate of [Unsigned hexadecimal constant in C?](http://stackoverflow.com/questions/4737798/unsigned-hexadecimal-constant-in-c) – Nemo Jul 18 '11 at 05:37
  • FWIW, gcc 4.6.1 on Linux, with `-Wall -ansi -pedantic` emitted just one warning, about control reaching end of non-void function. Possibly another feature that did not make it to the top of compiler writers' priority until very recently? – vpit3833 Jul 18 '11 at 06:56

5 Answers5

12

The answer to Unsigned hexadecimal constant in C? is relevant. A hex constant with L suffix will have the first of the following types that can hold its value:

long
unsigned long
long long
unsigned long long

See the C99 draft, section [ 6.4.4.1 ], for details.

On your platform, long is probably 32 bits, so it is not large enough to hold the (positive) constant 0x80000000. So your constant has type unsigned long, which is the next type on the list and is sufficient to hold the value.

On a platform where long was 64 bits, your constant would have type long.

jww
  • 97,681
  • 90
  • 411
  • 885
Nemo
  • 70,042
  • 10
  • 116
  • 153
  • 1
    What makes compiler treat 0x80000000 as a (positive) constant? Could you provide standard reference here? Assuming if int is 32 bits wide, why can 0x80000000 not be represented by an int? Does that then mean that Hexadecimal inherently are positive? For a decimal 1, it's negative would be -1. Does then "-" operator applicable to hexadecimals as well? Somehow I am unable to find a convincing reference that documents this. – Cheshar Jul 18 '18 at 15:27
  • 2
    @cheshar: Try the reference I gave (C99 draft, section 6.4.4.1); it is perfectly clear. It says "The value of a decimal constant is computed base 10; that of an octal constant, base 8; that of a hexadecimal constant, base 16". So `0x80000000` is computed base 16 and has value 2^31. Its type is the first on the list that can represent that value. A 32-bit signed `int` cannot represent that value (because it is larger than `INT_MAX`), so that is not its type. – Nemo Jul 18 '18 at 21:50
  • Uh yes, I read that part but never paid much attention to it. Thank you for clarifying this. I guess it makes much more sense now. So basically then, 0x80000000 is not a negative number really then. It's just a hex number which represents a negative value for a 32 bit signed type right? Also, isn't it weird then that (-0x80000000) is not a negative number? Because for decimal numbers, anything prefixed by (-)operator represents a negative value. More specifically why decimal constants go from - int, long int, long long int whereas hex constants have unsigned as well? – Cheshar Jul 19 '18 at 05:42
  • 1
    @Cheshar: Almost, but not exactly. If you do `unsigned n = 1`, the expression `-n` still has type `unsigned` and is _positive_ (2^32-1 for 32-bit ints). Same principle applies to `-0x80000000`; both the operand and the result of the unary `-` are unsigned and thus positive. Decimal constants are always signed (unless you suffix `u`), so `-` gives a negative result. I agree the rules are weird, and I do not know why they were chosen this way. That might make a fair SO question... – Nemo Jul 19 '18 at 16:01
1

Because your compiler uses 32-bit longs (and presumably 32-bit ints as well) and 0x80000000 wont fit in a 32-bit signed integer, so the compiler interprets it as unsigned. How to work around this depends on what you're trying to do.

David X
  • 3,998
  • 3
  • 29
  • 32
0

It's an unsigned long then. I'm guessing the compiler decides that a hex literal like that is most likely desired to be unsigned. Try casting it (unsigned long)0x80000000L

Paul
  • 139,544
  • 27
  • 275
  • 264
0

Hex constants in C/C++ are always unsigned. But you may use explicit typecast to suppress warning.

qoyllur
  • 29
  • 2
  • 2
    Hex constants in C/C++ are _not_ always unsigned. They are always positive, which is not the same thing at all. – Nemo Jul 18 '11 at 05:40
  • @Nemo You're right about hex constants. I found another strange behavior. I modified example changing comparsion to below: `if((long long)*p != LLONG_MAX) printf("test");` and compiler gives me ``warning: comparison is always true due to limited range of data type`` – qoyllur Jul 18 '11 at 06:19
  • @Nemo Hi nemo, if you like submit a detailed answer explaining the difference with some examples and I will mark it as correct. Otherwise I will submit what you wrote and expand on the substance and mark it correct, as it appears to be the correct answer from what I can tell. Contrary to what I thought, it appears hexadecimal constants do not take a suffix! [ms docs link](http://msdn.microsoft.com/en-us/library/2k2xf226.aspx) – test Jul 19 '11 at 03:59
  • @test: Huh? Even according to the page you link, "integer-constant" has a production rule "hexadecimal-constant integer-suffix". Hex constants absolutely do take a suffix; they just work a little differently than decimal constants. I will write up my answer. – Nemo Jul 19 '11 at 04:48
  • @Nemo yes, you are correct, it appears I misread that document. – test Jul 20 '11 at 00:50
-1

According to the c standard hex constants are unsigned.

steve
  • 5,870
  • 1
  • 21
  • 22
  • 9
    Not true in general... Hex constants will be signed if the signed variant is sufficient to hold the value. See http://stackoverflow.com/questions/4737798/unsigned-hexadecimal-constant-in-c. (In particular, if "long" were 64 bits, this constant would be signed, not unsigned.) – Nemo Jul 18 '11 at 05:32