Re: 3), here's a clean and technically humble way that I typically use.
enum {
KEY_FOO,
KEY_BAR,
KEY_BLAH,
NUM_KEYS,
};
struct KeyInfo {
const char *name;
int info1;
float info2;
};
const static struct KeyInfo keyInfo[NUM_KEYS] = {
#define MAKE(x, y, z) [x] = { #x, y, z }
MAKE( KEY_FOO, 1, 1.0 ),
MAKE( KEY_BAR, 7, 3.5 ),
MAKE( KEY_BLAH, 42, 127.2 ),
#undef MAKE
};
void print_key(int key)
{
printf("%d's name is %s\n", key, keyInfo[key].name);
}
It's both low-tech and maintainable. It compiles super quick. If one doesn't like that one has to type KEY_FOO twice (in the enum and in the array definition), one can use X-macros or code generation. But personally I don't care.