Detect when multiple enum items map to same value

c, c++, duplicates, enums

Solution

There are a couple ways to check this compile time, but they might not always work for you. Start by inserting a "marker" enum value right before MsgFoo2A.

typedef enum
{
    MsgFoo1A = BASE1_VAL,
    MsgFoo1B,
    MsgFoo1C,
    MsgFoo1D,
    MsgFoo1E,
    MARKER_1_DONT_USE, /* Don't use this value, but leave it here.  */
    MsgFoo2A = BASE2_VAL,
    MsgFoo2B
} FOO;

Now we need a way to ensure that `MARKER_1_DONT_USE < BASE2_VAL` at compile-time. There are two common techiques.

Negative size arrays

It is an error to declare an array with negative size. This looks a little ugly, but it works.

extern int IGNORE_ENUM_CHECK[MARKER_1_DONT_USE > BASE2_VAL ? -1 : 1];

Almost every compiler ever written will generate an error if MARKER_1_DONT_USE is greater than BASE_2_VAL. GCC spits out:

test.c:16: error: size of array ‘IGNORE_ENUM_CHECK’ is negative

Static assertions

If your compiler supports C11, you can use `_Static_assert`. Support for C11 is not ubiquitous, but your compiler may support `_Static_assert` anyway, especially since the corresponding feature in C++ is widely supported.

_Static_assert(MARKER_1_DONT_USE < BASE2_VAL, "Enum values overlap.");

GCC spits out the following message:

test.c:16:1: error: static assertion failed: "Enum values overlap."
 _Static_assert(MARKER_1_DONT_USE < BASE2_VAL, "Enum values overlap.");
 ^

Problem

Is there a compile-time way to detect / prevent duplicate values within a C/C++ enumeration? The catch is that there are multiple items which are initialized to explicit values. Background: I've inherited some C code such as the following: ``` #define BASE1_VAL (5) #define BASE2_VAL (7) typedef enum { MsgFoo1A = BASE1_VAL, // 5 MsgFoo1B, // 6 MsgFoo1C, // 7 MsgFoo1D, // 8 MsgFoo1E, // 9 MsgFoo2A = BASE2_VAL, // Uh oh! 7 again... MsgFoo2B // Uh oh! 8 again... } FOO; ``` The problem is that as the code grows & as developers add more messages to the `MsgFoo1x` group, eventually it overruns `BASE2_VAL`. This code will eventually be migrated to C++, so if there is a C++-only solution (template magic?), that's OK -- but a solution that works with C and C++ is better.

Original source

Related problems