Ivan
Ivan

Reputation: 191

different size of the same enum type

The sizes of enum types in the following code are different, why? Will the declararation of an enum type will cause gcc to treat it as signed int? And this feature cause a problem in my project, for example, the size of one enum type is 1 in "file_1.c", but the size of it is 4 in "file_2.c".

My test code:

enum foo foo_test(void);

enum foo {
    FOO_0
};

enum bar {
    BAR_0
};

int main(int argc, char **argv)
{
    printf("sizeof(enum foo) %d, sizeof(enum bar) %d\n", sizeof(enum foo), sizeof(enum bar));
    return 0;
}

Upvotes: 5

Views: 347

Answers (4)

As is so common with the questions asking about peculiar outcomes in , the reason here is undefined behaviour. The C11 standard draft n1570 6.7.2.3p3:

  1. A type specifier of the form

    enum identifier
    

    without an enumerator list shall only appear after the type it specifies is complete.

And of completeness in C11 6.7.2.2p4:

  1. [...] The enumerated type is incomplete until immediately after the } that terminates the list of enumerator declarations, and complete thereafter.

As a shall in a constraints section was violated, a conforming compiler must output a diagnostics message - however GCC by default isn't a conforming implementation unless you ask it to be -pedantic:

ISO C forbids forward references to ‘enum’ types [-Werror=pedantic]
 enum foo foo_test(void);
      ^

Now, it seems that the compiler there uses the shortest possible enums for any type. Since you used the enum foo before it was actually defined what was in there, the compiler had to resort to int for its type, otherwise char was used. It can be reproduced with -fshort-enums. Your program prints 4 1, whereas this program prints 1 1 with -fshort-enums on my gcc.

#include <stdio.h>

enum foo {
    FOO_0
};

enum foo foo_test(void);    

enum bar {
    BAR_0
};

int main(int argc, char **argv)
{
    printf("sizeof(enum foo) %zu, sizeof(enum bar) %zu\n", 
            sizeof(enum foo), sizeof(enum bar));
    return 0;
}

Upvotes: 6

Bathsheba
Bathsheba

Reputation: 234715

First of all, fix the undefined behaviour in your code. The correct format specifier for the sizeof expression type is %zu.

The backing type of an enumerator in C can be char, int, or unsigned. The compiler can pick any of these so long as it is capable of storing all the enumerated values.

So a value of 1 is feasible (as sizeof(char) is always 1), and you have asked some of your compilers to squeeze the enum backing types.

The fact that an int appears to be chosen for the backing type for foo is due, I think, to your referring to enum foo before you define it, and your friendly C compiler is using some sort of implicit int. Such an implicit declaration is no longer standard C and your code is not strictly portable.

Reference: http://en.cppreference.com/w/c/language/enum

Upvotes: 4

0___________
0___________

Reputation: 67546

The answer is actually quite simple.

As you have function prototype returning enum type, the compiler assumes it as the int and its size is hardware dependent (in your case 4 bytes) It is done for the optimisation purposes. For the another one is stored in the smallest possible data type. (probably -Os optimisation and / or -fshort-enums were used)

For coders having the real programming experience this behaviour is well known, and that is the reason to do not declare functions as returning enums if you want to keep them short.

For C standard fanatics uint8_t foo(); and return FOO_0; might be unacceptable but the programming is a real, live and practical science.

Upvotes: -1

unwind
unwind

Reputation: 399861

This is undefined behavior.

You must use %zu to make printf() format a value of type size_t.

If the size of the value differs from that of int, the code in printf() will mis-read the varargs-argument and get the wrong idea of its value (va_arg(args, int); instead of va_arg(args, size_t);.

Upvotes: 2

Related Questions