Стрификация на член перечисления - PullRequest
1 голос
/ 03 октября 2009

Мне нужно преобразовать элемент перечисления (его значение, а не идентификатор) в строку. Я пробовал следующее, который работает для MACRO (TYPE_A), но не для значения enum (typeA). Это немного странно, на мой взгляд.

У вас есть идеи, как это сделать?


#define _tostr(a) #a
#define tostr(a) _tostr(a)

typedef enum _SPECIAL_FOLDER_ID {
    typeA = 3,
    typeB = 4,
} SPECIAL_FOLDER_ID;

#define TYPE_A 3

int main() {
    //this is working, but the information is a macro (TYPE_A)
    printf("The string is " tostr(TYPE_A) ".\n");

    //this is not working for typeA (defined in an enumeration)
    printf("The string is " tostr(typeA) ".\n");
    return 0;
}


Вывод:

The string is 3.
The string is typeA.

Мне нужно каким-то образом изменить код, чтобы вторая строка вывода была «Строка 3».

Спасибо!

PS: я не хочу печатать значение, используя printf. Мне нужна статическая строка, содержащая это значение. Я использую только printf для проверки результата ...

Ответы [ 7 ]

5 голосов
/ 03 октября 2009

Препроцессор не знает C. Он просто знает "текст".
Когда он обрабатывает ваш файл, typeA это всего лишь 5 букв. Только компилятор будет знать (после выполнения препроцессора), что typeA имеет значение и что значение равно 3.

3 голосов
/ 03 октября 2009

Нет действительно хорошего способа сделать это. Лучшее, что я мог придумать, это

#define typeA_ 3
#define typeB_ 4

enum
{
    typeA = typeA_,
    typeB = typeB_
};

#define tostr__(E) #E
#define tostr_(E) tostr__(E)
#define tostr(E) tostr_(E ## _)
2 голосов
/ 03 октября 2009

Что не так со следующим?

printf("The string is %d.\n", typeA );

Вы, кажется, несколько усложняете дела ...

1 голос
/ 03 октября 2009

Я склонен использовать подход статического массива. Это все еще клуге, но оно достаточно ясное и работает.

enum {
  typeA = 3,
  typeB = 4,
  NUM_LETTERS = 5
} Letters;

static const char* letterNames[NUM_LETTERS] {
  "", "", "",
  "3",
  "4"
};

printf("The string is " letterNames[(int)typeA] ".\n");

Похоже, что ответ Кристофа хорош, но я должен честно сказать, что я недостаточно знаком с макросами, чтобы понять его; -)

Редактировать; Другой способ: вы упоминаете, что вам нужна «статическая строка», но я не уверен, что она вам нужна во время компиляции. Можете ли вы использовать sprintf в начале выполнения? Это решение будет выглядеть примерно так ...

enum {
  typeA = 3,
  typeB = 4,
  NUM_LETTERS = 5
} Letters;


int main(void){
    char * typeAString = new char[sizeof("This is at least as long as the typeA string")];
    sprintf(typeAString, "This is the %d string", typeA);
    // use your string here
    return 0;
}

То, как я использовал new здесь, не то, что я бы порекомендовал, но оно показывает идею использования sprintf в вашей программе.

1 голос
/ 03 октября 2009

Использование двух вложенных макросов - хитрость, которая заставляет препроцессор расширять любые аргументы макроса (TYPE_A -> 3).

Однако значения перечисления не расширяются препроцессором, они расширяются компилятором.

0 голосов
/ 03 октября 2009

Не существует автоматического способа сделать это, так как компилятор преобразует ENUM в литеральные числа.

Самый простой способ - иметь статический массив строк и соблюдать осторожность, чтобы синхронизировать его.

имена символов [] [8] {"", "", "", "typeA", "typeB" и т. Д.}
Тогда просто используйте «names [typeA]»

Более безопасный способ - использовать функцию с большим оператором switch.

0 голосов
/ 03 октября 2009

Что не так со старым добрым форматированным выводом?

printf("The string is %d", typeA)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...