Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing name of #define by its value?

I have a C program with some definitions for error codes. Like this:

#define FILE_NOT_FOUND -2
#define FILE_INVALID -3 
#define INTERNAL_ERROR -4
#define ... 
#define ... 

Is it possible to print the name of the definition by its value? Like this:

PRINT_NAME(-2);

// output
FILE_NOT_FOUND
like image 604
Anton Horst Avatar asked Apr 05 '12 16:04

Anton Horst


5 Answers

In short, no. The easiest way to do this would be something like so (PLEASE NOTE: this assumes that you can never have an error assigned to zero/null):

 //Should really be wrapping numerical definitions in parentheses. 
#define FILE_NOT_FOUND  (-2)
#define FILE_INVALID    (-3) 
#define INTERNAL_ERROR  (-4)

typdef struct {
  int errorCode;
  const char* errorString;
} errorType;

const errorType[] = {
  {FILE_NOT_FOUND, "FILE_NOT_FOUND" },
  {FILE_INVALID,   "FILE_INVALID"   },
  {INTERNAL_ERROR, "INTERNAL_ERROR" },
  {NULL,           "NULL"           },
};

// Now we just need a function to perform a simple search
int errorIndex(int errorValue) {
  int i;
  bool found = false;
  for(i=0; errorType[i] != NULL; i++) {
    if(errorType[i].errorCode == errorValue) {
      //Found the correct error index value
      found = true;
      break;
    }
  }
  if(found) {
    printf("Error number: %d (%s) found at index %d",errorType[i].errorCode, errorType[i].errorString, i);
  } else {
    printf("Invalid error code provided!");
  }
  if(found) {
    return i;
  } else {
    return -1;
  }
}

Enjoy!

Additionally, if you wanted to save on typing even more, you could use a preprocessor macro to make it even neater:

#define NEW_ERROR_TYPE(ERR) {ERR, #ERR}
 const errorType[] = {
      NEW_ERROR_TYPE(FILE_NOT_FOUND),
      NEW_ERROR_TYPE(FILE_INVALID),
      NEW_ERROR_TYPE(INTERNAL_ERROR),
      NEW_ERROR_TYPE(NULL)
    };

Now you only have to type the macro name once, reducing the chance of typos.

like image 129
Cloud Avatar answered Oct 13 '22 17:10

Cloud


You can do something like this.

#include <stdio.h>

#define FILE_NOT_FOUND -2
#define FILE_INVALID -3 
#define INTERNAL_ERROR -4

const char* name(int value) {
#define NAME(ERR) case ERR: return #ERR;
    switch (value) {
        NAME(FILE_NOT_FOUND)
        NAME(FILE_INVALID)
        NAME(INTERNAL_ERROR)
    }
    return "unknown";
#undef NAME
}

int main() {
    printf("==== %d %s %s\n", FILE_NOT_FOUND, name(FILE_NOT_FOUND), name(-2));
}
like image 30
Ziffusion Avatar answered Oct 13 '22 17:10

Ziffusion


No, that's not possible. What would this print?

#define FILE_NOT_FOUND   1
#define UNIT_COST        1
#define EGGS_PER_RATCHET 1

PRINT_NAME(1);
like image 42
RichieHindle Avatar answered Oct 13 '22 17:10

RichieHindle


Kinda ...

#define ERROR_CODE_1 "FILE_NOT_FOUND"
#define ERROR_CODE_2 "FILE_FOUND"

#define PRINT_NAME(N) ERROR_CODE_ ## N

or:

static char* error_codes(int err) {
   static char name[256][256] = {

   };
   int base = .... lowest error code;
   return name[err - base];
}

#define PRINT_NAME(N) error_code(N)
like image 2
Anycorn Avatar answered Oct 13 '22 17:10

Anycorn


Why not elect to use an enumeration instead?

enum errors {FILE_NOT_FOUND = -2, FILE_INVALID = -3, INTERNAL_ERROR = -4};

FILE *fp = fopen("file.txt", "r");


if(fp == NULL) {
    printf("Error\n");
    exit(FILE_NOT_FOUND);
}
like image 1
Makoto Avatar answered Oct 13 '22 15:10

Makoto