Thursday, February 9, 2012

GCC and unsigned enumerations

Enumerations in C are signed or unsigned in GCC depending on whether
one of the values is negative. This prohibits forward-looking checks
that expect that enumerations may include a negative value in the
future.

For example, say we had silly color_t enumeration:

typedef enum { RED = 0, GREEN = 1 } color_t;
const char * string_of_color (color_t color) {
    static const char * colors[2] = { "RED", "GREEN" };
    return colors[color];
}
int main(void) {
    printf("Color: %s\n", string_of_color(0));
}

The output will be:

Color: RED

The program may crash if main was to call string_of_color(10). So we'll put in a check:

typedef enum { RED = 0, GREEN = 1 } color_t;
const char * string_of_color (color_t color) {
    static const char * colors[2] = { "RED", "GREEN" };
    if (color < 0 || color > 1) return "INVALID";
    return colors[color];
}
int main(void) {
    printf("Color: %s\n", string_of_color(0));
}

But now GCC complains:

warning: comparison of unsigned expression < 0 is always false

This breaks things because I might expect that we'd change the color enumeration to:

typedef enum { INVALID = -1, RED = 0, GREEN = 1 } color_t;

Now my check is valid and GCC doesn't complain. My workaround?

if ((int)color < 0 || color > 1) return "INVALID";

Another possible workaround is to add a negative value in color_t or use a GCC compile-time option.

0 comments:

Post a Comment