Does C treat hexadecimal constants (e.g. 0x23FE) and signed or unsigned int?
3 Answers
The number itself is always interpreted as a non-negative number. Hexadecimal constants don't have a sign or any inherent way to express a negative number. The type of the constant is the first one of these which can represent their value:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
- 700,257
- 99
- 619
- 646
-
I lack the expertise to declare this correct, but it makes more sense than the other answer. – Jan 19 '11 at 16:54
-
1Note that as a consequence, 0x8000 may be either signed or unsigned depending on whether sizeof(int) is 2 or 4. Yuck! Just append `u` if you really need `unsigned`. – anatolyg Jan 19 '11 at 17:15
-
2@anatolyg: I'm not sure what you mean by "yuck". It will always be positive and it will always convert to the correct value if assigned or promoted to another type where the value is still in range which seems like fairly sensible and desirable behaviour to me. – CB Bailey Jan 19 '11 at 17:18
-
@Charles I mean: `#define MYSIZE 0x8000`; somewhere later in code `if (MYSIZE > 0x7000) {...}` - behaves surprisingly if 0x8000 is negative – anatolyg Jan 19 '11 at 18:25
-
Thanks. I wasn't aware that you could add the 'u' suffix to a hex number. – Amr Bekhit Jan 19 '11 at 20:00
-
2@anatolyg: But `0x8000` isn't negative. Either it can fit in an `int`, in which case `0x8000 > 0x7000` is done as a comparison of `int`, otherwise `0x8000` is an `unsigned` and `0x7000` is promoted to `unsigned` (no change of value) and the comparison is a comparison of `unsigned`. Either way the result is true. – CB Bailey Jan 19 '11 at 20:35
-
2Decimal and octal constants don't have a sign either - if you write `-1`, you're writing a unary `-` followed by a decimal constant `1`. In @anatolyg's example, `if (MYSIZE > -1)` could produce surprising results, since the `-1` may or may not be promoted to unsigned. – caf Jan 20 '11 at 00:20
-
1@caf: `0x8000 > -1` is a much better example of where care definitely is needed. – CB Bailey Jan 20 '11 at 07:50
-
@CharlesBailey - How does one work around this issue: [Job #506.2 Failure](https://travis-ci.org/Tarsnap/scrypt/jobs/360781179). I've tried `0xE9B5DBA5B5C0FBCF`, `0xE9B5DBA5B5C0FBCFLL` and `0xE9B5DBA5B5C0FBCFULL`, but Clang rejected all of them. (The code came from Intel, and I doubt it is defective). – jww Apr 01 '18 at 03:44
-
1@CBBailey: Regarding "Hexadecimal constants don't have a sign or any inherent way to express a negative number" - Can you provide a reliable source/reference which mentions/documents this? Does that mean that Hexadecimals number system doesn't support negative numbers? – Cheshar Jul 18 '18 at 15:32
-
1It's not true that hex literals don't have a sign. They do. You can qualify `0x23FEU` if you want unsigned, but `0x23FE` is signed. – Alex Apr 02 '20 at 12:09
It treats them as int literals(basically, as signed int!). To write an unsigned literal just add u at the end:
0x23FEu
- 91,294
- 38
- 174
- 232
-
3I don't think that you can leave that statement as such. E.g provided that the width of `int` is 32 bit the value `0x8000` is `unsigned` (namely `INT_MAX + 1`) and not `signed` (and `INT_MIN`). – Jens Gustedt Jan 19 '11 at 16:40
-
2@JensGustedt: Presumably you mean that if the width of `int` is **16** bit then `0x8000` will be `unsigned`? – CB Bailey Jan 19 '11 at 16:43
-
1@Charles, probably. Counting bits myself never was my strength :) – Jens Gustedt Jan 19 '11 at 16:56
-
@JensGustedt what you say is not true. The hex literal `0x8000` is signed, just like the equivalent literal `32768` is signed. What you're saying makes no sense. Just because the value of a literal is equal to `INT_MAX + 1` for a 16-bit integer doesn't change anything about its type's signedness. `0x8000` is signed. If you want unsigned, you need to qualify the literal accordingly as `0x8000U`. – Alex Apr 02 '20 at 12:21
-
1@Alex, no. A hexadecimal value is `int` as long as the value fits into `int` and for larger values it is `unsigned`, then `long`, then `unsigned long` etc. See Section 6.4.4.1 of the C standard. Just as the accepted answer states. – Jens Gustedt Apr 02 '20 at 13:26
-
@JensGustedt my bad, I did not know that the signedness in the interpretation alternates (also, super-weird that it is that way). – Alex Apr 02 '20 at 16:52
According to cppreference, the type of the hexadecimal literal is the first type in the following list in which the value can fit.
int
unsigned int
long int
unsigned long int
long long int(since C99)
unsigned long long int(since C99)
So it depends on how big your number is. If your number is smaller than INT_MAX, then it is of type int. If your number is greater than INT_MAX but smaller than UINT_MAX, it is of type unsigned int, and so forth.
Since 0x23FE is smaller than INT_MAX(which is 0x7FFF or greater), it is of type int.
If you want it to be unsigned, add a u at the end of the number: 0x23FEu.
- 22,811
- 37
- 122
- 172
-
This answer appears to pertain to C++, not C. It may be correct, but I think the reference link should be updated to point to the C reference, not the C++ reference. – Radon Rosborough Sep 13 '18 at 00:25
-
2@RadonRosborough I've updated the answer to use the C reference and checked the other parts of it to make sure the answer was all about C. Thanks for pointing it out. – Searene Sep 13 '18 at 00:49