2
typedef enum
{
    eval1,
    eval2,
    eval3
} enum_t;
_Static_assert(sizeof(enum_t) == 1, "enum_t must be 1 byte");
char dummy[sizeof(enum_t) == 1];

This code compiles if the _Static_assert is commented out. The fact that dummy compiles should mean that sizeof(enum_t) == 1 evaluates to true.

Why is my _Static_assert not working?


Additional cases:

_Static_assert(sizeof(enum_t) >= 1, "");   // Passes
_Static_assert(sizeof(enum_t) == 1, "");   // Fails
_Static_assert(sizeof(enum_t) > 1, "");    // Fails
_Static_assert(!(sizeof(enum_t) > 1), ""); // Fails

I am using clang 13.0.0.

My command-line is: "C:/Program Files/SEGGER/SEGGER Embedded Studio for ARM 5.68/llvm/bin/clang" -cc1 -disable-free -disable-llvm-verifier -fgnuc-version=4.2.1 -mrelocation-model static -mconstructor-aliases -x c -fno-caret-diagnostics -fno-diagnostics-fixit-info -std=c17 -triple thumbv6m-none-eabi -target-cpu cortex-m0 -target-feature +strict-align -target-feature +soft-float -target-feature +soft-float-abi -msoft-float -target-abi aapcs -mfloat-abi soft -fno-signed-char -fallow-half-arguments-and-returns -mllvm -arm-global-merge=false -nostdsysteminc -nobuiltininc "-isystemC:/Program Files/SEGGER/SEGGER Embedded Studio for ARM 5.68/segger-rtl/include" "-isystemC:/Program Files/SEGGER/SEGGER Embedded Studio for ARM 5.68/include" -D__SIZEOF_WCHAR_T=4 -D__ARM_ARCH_6M__ -D__SES_ARM -D__HEAP_SIZE__=0 -D__SES_VERSION=56800 -D__SEGGER_LINKER -DDEBUG=1 -DUSE_RTT=1 -DSTM32G031xx -D__STM32G0xx_FAMILY -D__STM32G031_SUBFAMILY -DARM_MATH_CM0PLUS -sys-header-deps -Werror -dwarf-version=4 -debug-info-kind=standalone -debug-info-macro -debugger-tuning=gdb -mllvm -generate-arange-section -exception-model=dwarf -gpubnames -fno-dwarf-directory-asm -fmath-errno -ffunction-sections -fdata-sections -fshort-enums -fno-common test.c -emit-obj -o test.o -Wall -Wextra -Wpedantic -ffunction-sections -fdata-sections

Graznarak
  • 3,626
  • 4
  • 28
  • 47
  • 2
    Maybe your compiler allows zero-size arrays as an extension? Try `sizeof(enum_t) == 1 ? 1 : -1` as the size. – HolyBlackCat Jan 21 '22 at 16:41
  • @HolyBlackCat I verified that my compiler gives me an error on a 0-sized array. – Graznarak Jan 21 '22 at 16:43
  • 2
    Please try the array size I suggested. – HolyBlackCat Jan 21 '22 at 16:43
  • That does give me an error. If I change it to `char dummy[sizeof(enum_t)];` I can see that `dummy` has a size of 1 in my map file. So, what am I doing wrong? – Graznarak Jan 21 '22 at 16:48
  • I wouldn't trust the map file. It probably means that your compiler allows zero-size arrays in certain situations (when the zero is computed and not hardcoded, perhaps?). I couldn't reproduce this (either all zero-size arrays are rejected, or all are accepted, depending on flags). What compiler did you use, including version and flags? – HolyBlackCat Jan 21 '22 at 16:49
  • 2
    You were *so* close to giving a [mcve] but for some reason you chose to replace a critical part with `...`. Next time, it would be better to give compilable code so people can easily help you out without guesswork. – David Grayson Jan 21 '22 at 16:57
  • 1
    @hyde I work in embedded systems. Adding `main` and printing the size is non-trivial. Hence I tend to look at the map file. – Graznarak Jan 21 '22 at 17:48
  • 1
    @Graznarak: You can add `void foo(void) { __asm__("# sizeof (enum_t) = %0" : : "i" (sizeof (enum_t)) ); }`, compile with `-S` to generate assembly, and then look in the assembly for the “# sizeof (enum_t) = ” line. – Eric Postpischil Jan 21 '22 at 18:02
  • Does this answer your question? [Is the sizeof(enum) == sizeof(int), always?](https://stackoverflow.com/questions/1113855/is-the-sizeofenum-sizeofint-always) – user3840170 Jan 21 '22 at 18:11
  • @user3840170: No, that is not relevant. The issue here is not particularly what the size of the enumeration type is but why `_Static_assert` and the array declaration test appear to be indicating conflicting things. – Eric Postpischil Jan 21 '22 at 18:12
  • @EricPostpischil If that is so, then it should be clarified in the question body. – user3840170 Jan 21 '22 at 18:16
  • @user3840170: The body states the fact that the declaration of `dummy` compiles indicates the expression evaluates as true, conflicting with the `_Static_assert`. The body explicitly asks the question “Why is my `_Static_assert` not working?”, not “Why is the size not one byte?” – Eric Postpischil Jan 21 '22 at 18:20
  • I have tried testing the enum size against 1, 2, 4, 8. All fail. Also note the additional `_Static_assert` lines that were added to the question. – Graznarak Jan 21 '22 at 18:41
  • See also: https://stackoverflow.com/questions/1113855/is-the-sizeofenum-sizeofint-always?noredirect=1&lq=1 – Andrew Jan 21 '22 at 18:44
  • If I remove the `-fshort-enums` comand-line argument, then `_Static_assert` works as expected. It appears that there is a bug related to `sizeof()` when `-fshort-enums` is used and finding the size of an enum. – Graznarak Jan 21 '22 at 18:55

2 Answers2

0

Some compilers accept 0-length arrays. For example, testing GCC 11.2 on Godbolt.org, we can see that GCC happily compiles a 0-length array and only warns about it if the -pedantic option is used.

Therefore, you should not assume that just because char foo[x]; compiles that x is positive. If you don't want to use _Static_assert and instead want to do your assertions with using array sizes for some reason, you can do something like:

char foo[condition ? 1 : -1];
David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • Why reach for flimsy empirical testing on Godbolt, when you have [official documentation](https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Zero-Length.html#Zero-Length)? – user3840170 Jan 21 '22 at 18:15
-1

The C standard states that each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type - and that the choice of type is implementation-defined. (ISO/IEC 9899:2018 6.7.2.2 4)

Thus, typically, in C an enum is an integer type not a char and so I would expect:

sizeof(enum_t) == sizeof(int)

Thus, for a typical 32 bit system, sizeof(int) is 4 - I suspect this is what you are seeing...

Some compilers do have a language extension that allows you to specify the size of the enumerated type... standardising this has been discussed, but it is not in C18 nor (yet!) a candidate for C2X.

Andrew
  • 2,046
  • 1
  • 24
  • 37
  • Enumeration constants have type `int`, but an enumeration type itself has a type compatible with `char`, a signed integer type, or an unsigned integer type, per C 2018 6.7.2.2 4. So it can be one byte. – Eric Postpischil Jan 21 '22 at 18:07
  • Let me expand my answer then... you are quite right that the Standard *allows* that... – Andrew Jan 21 '22 at 18:43
  • See also https://stackoverflow.com/questions/1113855/is-the-sizeofenum-sizeofint-always?noredirect=1&lq=1 – Andrew Jan 21 '22 at 18:44