1

If I have a bunch of error codes in my application header.h like:

enum errors {
    ERROR_NONE,
    ERROR_TOTO,
    ERROR_TATA,
    ERROR_TUTU,
    ERROR_MAX,
};

Should I define the string associated with each code in the header like this:

static const char * const errors_strings[ERROR_MAX] = {
    "ERROR_NONE",
    "Something happened with toto",
    "Tata is wrong",
    "Pasta or pizza?",
};

or directly in the printing function:

void print_error(int error)
{
    char* array[ERROR_MAX] = {
    "ERROR_NONE",
    "Something happened with toto",
    "Tata is wrong",
    "Pasta or pizza?"
    };
    printf("%s\n", errors_strings[error]);
}

Which is the better practice?

Ekid
  • 11
  • 2
  • 2
    In the printing function, or somewhere in the .c file where `print_error` is defined. Never _define_ anything in a header file, only _declare_ things in header files. – Jabberwocky Mar 21 '22 at 12:39
  • 1
    Even in the function I would define the array as `const` and `static`. As for which is "best" that is mostly subjective, but for your case could be answered if you can answer this question: When and where will this array be accessed from? Only from inside the `print_error` function? Or from somewhere else? – Some programmer dude Mar 21 '22 at 12:39
  • @Someprogrammerdude Since it would only be accessed from this function I guess it makes more sense to define it inside. But why define a local variable as `const`, and I thought `static` on modern processor was pretty useless, especially since the function will only be called once. – Ekid Mar 21 '22 at 13:03
  • If you take internationalization (i18n) into account, there are more solutions. – the busybee Mar 21 '22 at 13:11
  • First of all, literal strings in C can't be modified, they are in essence read-only. Therefore one should use `const char *` to point to literal strings. Secondly, even if the code doesn't modify the array, it doesn't hurt to explicitly tell the compiler that by making it `const` as well. And finally, it doesn't make sense to create and initialize a new array each and every call to the function, so make it `static`. – Some programmer dude Mar 21 '22 at 13:12
  • Also, in C enumerations are really nothing more that named `int` constant values. Nothing stops a user from passing any `int` value to your function, so you really should have some range checks to make sure you don't access the array out of range. – Some programmer dude Mar 21 '22 at 13:15

1 Answers1

0

First of all, make the error enum a named type with typedef. Ideally we shouldn't mix int and enum types but treat enum as distinct types, even though the weak type system in C doesn't provide much help there. (However, check out How to create type safe enums? for some tips & tricks.)

As for if you should have the string table outside a function or inside one, it entirely depends on if one or several functions are using it. If only one function is using it, then it's a good idea to place the table inside it, to reduce its scope.


Also since the string array has size ERROR_MAX it cannot hold more initialized items than that, but nothing prevents it from having less. Therefore to guarantee integrity between the enum and the table, always do this:

static const char * const errors_strings[] = { ... }; // no size specified

_Static_assert(sizeof errors_strings / sizeof *errors_strings == ERROR_MAX,
               "helpful error message here");
Lundin
  • 195,001
  • 40
  • 254
  • 396