0

I've encountered some interesting behavior with gcc's interpretation of the signedness of constants. I have a piece of code which (greatly simplified) looks like the below:

#define SPECIFIC_VALUE 0xFFFFFFFF

//...

int32_t value = SOMETHING;
if (value == SPECIFIC_VALUE) {
    // Do something
}

When I compile the above, I get the warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

All well and good -- it seems that gcc interprets the hex constant as unsigned, and doesn't like the comparison to a signed integer. However, if I change the define to something like #define SPECIFIC_VALUE 0x7FFFFFFF, the warning goes away. Again, I'm not particularly surprised -- the sign bit being a zero would make gcc happier about interpreting the constant as a signed value. What really surprises me is that if I change the definition to be #define SPECIFIC_VALUE INT32_C(0xFFFFFFFF), I STILL get the warning. I would expect explicitly telling the compiler to interpret my constant as a signed value would silence the warning.

Austin Glaser
  • 352
  • 1
  • 12
  • 1
    No `int32_t` can ever be equal to `0xFFFFFFFF`. If you want `-1`, write `-1`. – caf Jun 04 '15 at 01:20
  • `INT32_C(X)` is not in ISO C, but is supposed to apply the integer suffix for an `int32` to `X`. It isn't a cast. On a system with 32-bit int, there will be no suffix for 32-bit ints so this macro will have no effect on the argument. – M.M Jun 04 '15 at 02:05
  • @Matt McNabb `INT32_C(X)` is in C11 "Macros for minimum-width integer constants" §7.20.4.1 1 – chux - Reinstate Monica Jun 04 '15 at 03:34
  • @chux Oh cool. I was looking under inttypes.h but turns out it's in stdint.h – M.M Jun 04 '15 at 03:42

1 Answers1

3

Read C11 § 6.3.1.1 about the conversions applied to integers. § 6.4.4.1 ¶5 specifies the type given for an integer constant. gcc should stick to these rules.

The hex constant is actually unsigned (by the standard) int (presuming 32 bit integers). So that conforms and is not by chance!

If you clear the MSbit, the constant can be represented as (signed) int, however. So the comparison goes well. Still standard.

The third message is lacking the definition of INT32_C, so I cannot help with that. But I think you can solve that yourself now. Just keep in mind, that the error cannot be detected inside the `#define', but only after the macro has been expanded.

General rule is to either add U to the constant (yes, also for hex) if you really want unsigned. Or cast the constant:

#define UVALUE ((uint32_t)0x7FFFFFFF)

That would be even better here, as it does not rely on the size of int actually.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • @iharob: Thanks. Everyone seems to do this different. – too honest for this site Jun 04 '15 at 00:57
  • `((int32_t)0xFFFFFFFF)` overflows, since the maximum value of `int32_t` is `0x7FFFFFFF`. The value is *probably* going to be `-1`, but strictlyi speaking it's implementation-defined. – Keith Thompson Jun 04 '15 at 01:05
  • Yeah, I just tried that. Should have listened to my own advice actually. I only use hex for unsigned, that was my error: stick to your pattern. Edited (yes: both changes are intented). – too honest for this site Jun 04 '15 at 01:08
  • Ok, that should be ok now. – too honest for this site Jun 04 '15 at 01:19
  • Many compilers use different integer literal rules if not invoked in standard-conforming mode – M.M Jun 04 '15 at 02:02
  • @MattMcNabb: 1) I generally presume standard conformance if not mentioned otherwise. 2) Too lazy to verify, but iirc gcc does not change _that_ behaviour in gnu-mode (does it actually change any of the standard behaviour or just enable its extensions? And does any extension change standard behavior? - Hmm, I might check that some day). – too honest for this site Jun 04 '15 at 02:07
  • @Olaf one difference that comes to mind is that some constants that would be `unsigned int` in ISO C90 are taken as `long long` in GNU89 (the default mode) – M.M Jun 04 '15 at 02:10
  • @MattMcNabb: From gcc 4.8.4 manual: "The default, if no C language dialect options are given, is -std=gnu90" (pew, lucky me;-). For gcc 5.1 it is even C11 (which surprises me a bit, I had assumed C99 as being the most commonly used, I think). – too honest for this site Jun 04 '15 at 02:13