2012-04-05 17 views
6

Mam program C z kilkoma definicjami kodów błędów. W ten sposób:Drukowanie nazwy #define według jej wartości?

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

Czy możliwe jest wydrukowanie nazwy definicji według jej wartości? W ten sposób:

PRINT_NAME(-2); 

// output 
FILE_NOT_FOUND 
+0

Myślę, że nie można zrobić czegoś podobnego w C. Może w jakimś języku z OOP, jak C# i refleksje. – Jack

+0

c preprocesor zastępuje nazwy. Potrzebujesz refleksji. możesz użyć CERN Reflections https://root.cern.ch/how/how-use-reflex https://stackoverflow.com/questions/359237/why-does-c-not-have-reflection – katta

Odpowiedz

3

Nie, to niemożliwe. Co by to wydrukować?

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

PRINT_NAME(1); 
1

Kinda ...

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

#define PRINT_NAME(N) ERROR_CODE_ ## N 

czyli

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) 
1

Dlaczego nie zdecydować się na zastosowanie zamiast wyliczenie?

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); 
} 
5

W skrócie, nie. Najprostszym sposobem na to byłoby coś podobnego tak (UWAGA: ta zakłada, że ​​nigdy nie można mieć błąd przypisany do zera/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!

Dodatkowo, jeśli chcesz zaoszczędzić na pisanie nawet więcej, można użyć preprocesora makra, aby go nawet 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) 
    }; 

Teraz trzeba tylko wpisać nazwę makra raz, co zmniejsza szansę literówki.

+0

+1 Wygląda to w jedną stronę. – Jack

1

Nie automatycznie. Nazwa traci podczas kompilacji, a tylko liczba stała pozostaje w kodzie.

Ale można zbudować coś takiego:

const char * a[] = {"","","FILE_NOT_FOUND","FILE_INVALID"}; 

i uzyskać do niego dostęp za pomocą określenia wartości bezwzględnej wartości jako wskaźnika.

1

Użyj do tego wyznaczonych inicjalizatorów C99, ale należy zachować ostrożność, jeśli kody błędów są ujemne.

Pierwsza wersja dla wartości dodatnich:

#define CODE(C) [C] = #C 

static 
char const*const codeArray[] = { 
CODE(EONE), 
CODE(ETWO), 
CODE(ETHREE), 
}; 

enum { maxCode = (sizeof codeArray/ sizeof codeArray[0]) }; 

Ten alokuje tablicę o długości że trzeba iz wskaźników łańcuch na właściwych pozycjach. Zwróć uwagę, że zdublowane wartości są dozwolone przez standard, ostatni to ten, który jest faktycznie przechowywany w tablicy.

Aby wydrukować kod błędu, należy sprawdzić, czy indeks jest mniejszy niż maxCode.

Jeśli kody błędów są zawsze ujemne, wystarczy je zanegować przed rozpoczęciem drukowania. Ale prawdopodobnie dobrze jest zrobić to na odwrót: kody powinny być dodatnie i sprawdzić wartość zwrotu dla swojego znaku. Jeśli jest ujemny, kod błędu byłby negacją wartości.

0

To jak to zrobić w C:

< MyDefines.h>

#pragma once 

#ifdef DECLARE_DEFINE_NAMES 
// Switch-case macro for getting defines names 
#define BEGIN_DEFINE_LIST const char* GetDefineName (int key) { switch (key) { 
#define MY_DEFINE(name, value) case value: return #name; 
#define END_DEFINE_LIST } return "Unknown"; } 

#else 

// Macros for declaring defines 
#define BEGIN_COMMAND_LIST /* nothing */ 
#define MY_DEFINE(name, value) static const int name = value; 
#define END_COMMAND_LIST /* nothing */ 

#endif 

// Declare your defines 
BEGIN_DEFINE_LIST 

MY_DEFINE(SUCCEEDED,  0) 
MY_DEFINE(FAILED,   -1) 
MY_DEFINE(FILE_NOT_FOUND, -2) 
MY_DEFINE(INVALID_FILE, -3) 
MY_DEFINE(INTERNAL_ERROR -4) 
etc... 

END_DEFINE_LIST 

< MyDefineInfo.h>

#pragma once 
const char* GetDefineName(int key); 

< MyDefineInfo.c>

#define DECLARE_DEFINE_NAMES 
#include "MyDefines.h" 

Teraz można korzystać z zadeklarowaną switch-case makro gdziekolwiek tak:

< WhereEver.c>

#include "MyDefines.h" 
#include "MyDefineInfo.h" 

void PrintThings() 
{ 
    Print(GetDefineName(SUCCEEDED)); 
    Print(GetDefineName(INTERNAL_ERROR)); 
    Print(GetDefineName(-1); 
    // etc. 
} 
1

można zrobić coś takiego.

#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)); 
} 
+0

Najbardziej podoba mi się ta wersja, ponieważ w przeciwieństwie do rozwiązań opartych na tablicach, daje błąd kompilatora, jeśli zdarzy ci się mieć niejednoznaczne/duplikować kody błędów. – 5gon12eder