4

I am trying to compile the following code in C (armcc file.c):

typedef enum A
{
    JANUARY,
    FEBRUARY= 0xFFFFFFFF  /* Warning seen on this line */
}A;

int main()
{
    int max = 0xFFFFFFFF; /* No warning seen for this line*/
    ...
}

I get a warning only for the enum assignment and not for integer variable assignment though in my view no warning should be seen for both.

Warning is below:

Warning: #66-D: enumeration value is out of "int" range FEBRUARY= 0xFFFFFFFF

Am I missing something here?

pushkin
  • 9,575
  • 15
  • 51
  • 95
Quest
  • 41
  • 1
  • 1
    I'd say you should be getting a like warning for both. Insure all warnings are enabled. – chux - Reinstate Monica Jul 18 '18 at 16:50
  • Is 0xFFFFFFFF taken as unsigned 2^32, in which case it would be outside the range of signed int? Try (int)0xFFFFFFFF – iVoid Jul 18 '18 at 16:50
  • @chux I guess the warnings for these two things are given on different levels. Moreover it's ARM compiler where each warning type can be suppressed specifically, so one should check it is not.. – Eugene Sh. Jul 18 '18 at 16:56
  • Do you get a warning if you declare it `const int`? – Barmar Jul 18 '18 at 16:57
  • Should be something like `#68-D: integer conversion resulted in a change of sign`. [Like here](http://www.keil.com/support/man/docs/armerr/armerr_dom1365070466238.htm) – Eugene Sh. Jul 18 '18 at 16:59
  • @iVoid `(int)0xFFFFFFFF` may work, yet conceptual, I'd re-code as `FEBRUARY = -1`. – chux - Reinstate Monica Jul 18 '18 at 17:02
  • 2
    Probaby because these are two different things. First one is defining a constant, second one is assigning a variable. So different conversion rules apply here. – Eugene Sh. Jul 18 '18 at 17:03
  • 2
    [From here](http://port70.net/~nsz/c/c11/n1570.html#6.7.2.2p2): *The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.* – Eugene Sh. Jul 18 '18 at 17:05
  • 3
    ... and that's a language *constraint*, so conforming compilers are obligated to issue a diagnostic when it is violated. Conversion of an out-of-range value to a signed integer type, whether explicit or implicit, is not a constraint violation. – John Bollinger Jul 18 '18 at 17:18
  • @iVoid,chux: Yes (int)0xFFFFFFFF does work but what is not clear to me is why an explicit cast to int is needed when 0xFFFFFFFF is still a valid int and that is the reason why "int max = 0xFFFFFFFF" did not give an error. – Quest Jul 19 '18 at 04:19
  • @John, Eugene: Sorry about being a bit repetitive here but I am not seeing how 0xFFFFFFFF is not a value that is representable as int. This is still -1 (assuming 2's compliment) right? – Quest Jul 19 '18 at 04:23
  • @Quest, I'm hypothesizing the difference might be that you're not specifying the literal as unsigned. `0xFFFFFFFFU` is forcibly unsigned, whereas `0xFFFFFFFF` is no suffix. But as per the standard, if a hex literal without a suffix doesn't fit in `signed int`, `unsigned int` is tried next before assigning it a `long int` type. Hence, `0xFFFFFFFF` without `U` suffix is first tried for `signed int` where it doesn't fit and then `unsigned int` should be tried for type fitting, where it would fit. I'm not sure why ARM's compiler treats it differently. – iVoid Jul 19 '18 at 08:59
  • Further reading on integer literal suffixes and `U` suffix. https://stackoverflow.com/questions/45621041/defending-u-suffix-after-hex-literals and https://stackoverflow.com/questions/8108642/type-of-integer-literals-not-int-by-default – iVoid Jul 19 '18 at 09:07
  • @ivoid Why do you think Arm compiler is treating it differently? It is not... – Eugene Sh. Jul 19 '18 at 22:44
  • @EugeneSh. In this context, ARM compiler is giving the warning - I meant in that sense. But correlating with your replies on integer constant expression - I guess ARM compiler is treating it properly as per standard only. – iVoid Jul 20 '18 at 07:14
  • first example is definition of an enumeration, which many implementations do with a limited set of values. enums are internally represented as integers (can be of different size than `int`, e.g. byte size) and so, you can get a warning from a value as large as `0xffffffff`. Assume your `enum`s can be limited in range. – Luis Colorado Jul 20 '18 at 12:34
  • @Quest, Sorry to return so late to the conversation, but no, the integer constant `0xFFFFFFFF` is *not* -1 any more than is `99999999` or any other all-nines decimal constant. Hex constants correspond to positive numbers, but [their types are determined from their values and type suffix](http://port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). They are always positive, which is not only natural, but also necessary for the type determination rules to work consistently. – John Bollinger Jul 26 '18 at 15:25

1 Answers1

2

Int assignment produces -1 so its technically legal. Per Arm spec enum is implemented using smallest integer type so it produces error.

Enumerations An object of type enum is implemented in the smallest integral type that contains the range of the enum. The storage type of an enum is the first of the following, according to the range of the enumerators in the enum:

  • unsigned char if not using --enum_is_int
  • signed char if not using --enum_is_int
  • unsigned short if not using --enum_is_int
  • signed short if not using --enum_is_int
  • signed int
  • unsigned int except C with --strict
  • signed long long except C with --strict
  • unsigned long long except C with --strict.

Implementing enum in this way can reduce data size. The command-line option --enum_is_int forces the underlying type of enum to at least as wide as int.

sbh
  • 407
  • 4
  • 13