1
typedef enum {my_false, my_true = 5, my_maybe = 3} my_bool;

my_bool f(){return 2;}
int g(){return my_true;}

int main (){
    my_bool mb = f();
    int i = f();
    printf("%d--%d\n", mb==i, mb);

    mb = g();
    i = g();
    printf("%d--%d\n", mb==i, mb);

    return 0;
}

What is happening when a function returns enum?

As I see it, in my code, f() can return any number, even if it's not defined inside the my_bool enum, but it seems that no matter what I return (like 2 in my example, the value stored inside my_bool mb = f(); would 1 unless I return 0ormy_false.

  1. Is this what should happen? does enum decays immediately to int and thus has no problem with numbers that aren't defined in it?

  2. Why gcc generates warning: comparison between signed and unsigned integer expressions [-Wsign-compare]... printf("%d--%d\n", mb==i, mb);? isn't enum a signed int?

  3. why defining the same value with different identifiers ok? (i.e. typedef enum {xx = 1, yy = 1} zz;)
CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • `my_bool f()`...and then `return `..what did you expect? – Sourav Ghosh Aug 02 '17 at 09:02
  • 1
    `my_bool mb` will have exactly the integer returned by `f()` regardless whether this integer is assigned in `enum my_bool` or not. – Scheff's Cat Aug 02 '17 at 09:03
  • @SouravGhosh I didn't expect. I don't understand what enum should hold in this case... – CIsForCookies Aug 02 '17 at 09:04
  • Isn't 2 a trap representation for `my_bool`? – Ajay Brahmakshatriya Aug 02 '17 at 09:05
  • @Scheff so `enum` __is__ an `int` that allows me to return it with a nice and catchy name? – CIsForCookies Aug 02 '17 at 09:07
  • 1
    @AjayBrahmakshatriya no, every value of the underlying integer type is fine for a variable of an `enum` type. –  Aug 02 '17 at 09:08
  • 1
    Yes, AFAIK. It's an `int` or a `long long int` depending on the enumerator values. If I only could remember the exact rule... – Scheff's Cat Aug 02 '17 at 09:08
  • At least I found an SO Q&A: [SO: Is the sizeof(enum) == sizeof(int), always?](https://stackoverflow.com/q/1113855/7478597) – Scheff's Cat Aug 02 '17 at 09:10
  • 1
    @Scheff: "*Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined but shall be capable of representing the values of all the members of the enumeration.*" The enum identifiers have type `int`. –  Aug 02 '17 at 09:10
  • 1
    @CIsForCookies: All `enum` types are _integral_ types, just like `char` and `short` and `int`. That doesn't mean they're literally `int`, but you can cast from one integral type to another. – MSalters Aug 02 '17 at 09:11
  • @FelixPalmen Yepp. Read this in the link above... – Scheff's Cat Aug 02 '17 at 09:11
  • @FelixPalmen My doubt was because of this https://stackoverflow.com/a/13423732/2858773 answer. Specifically the paragraph starting with *Regarding Trap Representation...* – Ajay Brahmakshatriya Aug 02 '17 at 09:12
  • @AjayBrahmakshatriya I don't think the example in this answer is correct. An important property of a *trap representation* is that it causes undefined behavior when accessed, and I can't find any part in the C standard that states a value not corresponding to an `enum` member would be UB... –  Aug 02 '17 at 09:15
  • @AjayBrahmakshatriya If this would be the case, a lot of code using `enum` for *flags* would actually be undefined. –  Aug 02 '17 at 09:16
  • @FelixPalmen I agree. If we agree that the example given there is wrong, there is no confusion. – Ajay Brahmakshatriya Aug 02 '17 at 09:19

2 Answers2

2

Enums can take any value in their range. The range is defined by the bits needed to represent all enumerators. In your case, you need 3 bits for my_true, which gives a range 0-7.

Enumerators are essentially named constants, and there's no reason why you can't have two constants that happen to have the same value. Plenty of constants are in fact zero.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Is taking anything outside this range undefined behavior? – lilezek Aug 02 '17 at 09:04
  • But as far as I remember, the enum example is often used to explain trap representations. Isn't 2 a trap value for `my_bool`? – Ajay Brahmakshatriya Aug 02 '17 at 09:04
  • @AjayBrahmakshatriya: No. Not at all. No idea where that's coming from. – MSalters Aug 02 '17 at 09:05
  • @MSalters IIRC it was an SO answer. Let me find it. – Ajay Brahmakshatriya Aug 02 '17 at 09:05
  • @MSalters My doubt was because of this https://stackoverflow.com/a/13423732/2858773 answer. Specifically the paragraph starting with *Regarding Trap Representation...* – Ajay Brahmakshatriya Aug 02 '17 at 09:10
  • @AjayBrahmakshatriya: That shows a value _outside_ the range of enumerators. In that example, the enumerators require 1 bit, so the value `2` (which requires 2 bits) is outside the range. – MSalters Aug 02 '17 at 09:14
  • @CIsForCookies standard says that the underlying type has to be `char` or `unsigned int`. There are no N bits types which represents the enums. – 0___________ Aug 02 '17 at 09:14
  • @MSalters if that is the case, you cannot create trap representations with enums. Since you can't fir 2 bits in 1 bit. Even if you `memcpy` a 2 there, it will just take one of the possible 0 or 1. Is the example in the answer no correct? – Ajay Brahmakshatriya Aug 02 '17 at 09:15
  • @PeterJ: That's not an exhaustive list. Obviously the full list has to include types which can have negative values (the guaranteed range of `char` is just 0-127) – MSalters Aug 02 '17 at 09:15
  • @AjayBrahmakshatriya: I don't even know what you're trying to say there. The smallest possible object in C is a byte, which takes 8 bits. That can be 7 trap bits and one value bit. Copying a `2` would set the lowest trap bit to `1` – MSalters Aug 02 '17 at 09:17
  • @MSalters yes that is exactly what I meant (pardon my wordings if it was not clear). So it is not possible to create trap representations with enums and hence the example on that link is wrong? – Ajay Brahmakshatriya Aug 02 '17 at 09:18
  • @AjayBrahmakshatriya: Trap representations are never _guaranteed_. They are possible, but only _outside_ the binary range of enumerators. E.g. `2*(int)highest_enumerator` might be a trapping value, but `enumerator_A | enumerator_B` may not. – MSalters Aug 02 '17 at 09:24
  • @MSalters I can't find that possibility for enumerators in the standard, Could you give a hint in which paragraph to look for it please? –  Aug 02 '17 at 09:45
  • 1
    This answer "The range is defined by the bits needed to represent all enumerators" and spec's ""Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type." is contradictory. If I have an enumerator with values 1,2,3, it certainly must be able to encode at least values 0-127 and not just 1-3 or 0-3. – chux - Reinstate Monica Aug 02 '17 at 11:53
0

enums can be implemented as char ,int or unsigned int and it is left for the implementation. From the warning you get the information that your gcc compiler implements the unsigned int.

0___________
  • 60,014
  • 4
  • 34
  • 74