scanf () с перечислениями C ++ - PullRequest
       3

scanf () с перечислениями C ++

3 голосов
/ 08 августа 2010

Ниже приведена типичная ситуация в нашей кодовой базе.

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }

ConfigOption cfg1, cfg2;

sscanf(s, "%d", &cfg1);

Это внутреннее программное обеспечение для моделирования. Не распространяется. Простота обслуживания и правильность важны. Переносимость и пользовательский интерфейс - не совсем.

Проблема в том, что enum в C ++ - это не обязательно int. Таким образом, мы получаем предупреждение компилятора и можем получить некорректное поведение при использовании другого компилятора или при включенной оптимизации.

Одно из решений - просто привести &cfg к int*. Однако это не затронет случаи, когда компилятор решил выделить что-то отличное от int для enum.

Поэтому я предложил следующее решение:

template<typename T> inline
int& eint(T& enum_var) {
    assert(sizeof(T) == sizeof(int));
    return (int&)enum_var;
}

А теперь используется scanf следующим образом:

sscanf(s, "%d", &eint(cfg1));

Я хотел бы услышать мнения и другие (лучшие) решения вышеуказанной проблемы. Имейте в виду, что одна из целей - сделать код простым. Это не материал «производственного качества», и чем больше вы добавляете, тем сложнее становится обслуживание.

Ответы [ 4 ]

4 голосов
/ 08 августа 2010

Если у вас есть современный компилятор, например vs2010, вы можете указать размер элементов enum

enum class ConfigOption: unsigned int {CONFIG_1=1, CONFIG_2=2, CONFIG_3=3};

это новое в C ++ 0x

2 голосов
/ 08 августа 2010

Мое решение состояло бы в том, чтобы сделать перечисление минимальным. Это то, что Microsoft сделала для своих перечислений в своих заголовочных файлах DirectX (хороший прием, я должен признать).

Они установили размер перечисления равным int, добавив фиктивное перечисление следующим образом:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force32Bit = ~0UL
} MyEnum;

Теперь перечисление всегда будет , по крайней мере, размером с int.

Если вы хотите, вы можете взять это поверх ... Этот размер приводит к длинному и длинному перечислению:

typedef enum 
{
  fooo = 1,
  baar = 2,
  ___Force64Bit = ~0ULL
} MyEnum;

Я знаю, это не супер чистое решение. Я думаю, что такого решения не существует, и соблюдение минимального размера работало для меня до сих пор. Возможно, вам придется скорректировать код, если вы переходите с 32-64-битного кода, но обычно в таких ситуациях вам все равно приходится просматривать некоторые части кода, так что нет большой проблемы.

Кстати - извините за C-код, я знаю, что вопрос был помечен как C ++, но я из C-парней: -)

1 голос
/ 08 августа 2010

Почему бы просто не прочитать это как фактический int?

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 };
ConfigOption cfg1;

int i;
sscanf(s, "%d", &i);
cfg1 = i;

И таким образом вы также можете выполнять более полные проверки достоверности (например, проверять, что целое число чтения находится в диапазоне вашего типа enum).

(Конечно, если вас вообще беспокоит обнаружение ошибок, для такого простого анализа, как этот, вы должны использовать strtol или strtoul вместо sscanf.)

0 голосов
/ 08 августа 2010

Вы можете попробовать использовать boost::lexical_cast, или если вы не используете boost и не хотите начинать использовать его только для этого случая, вы можете просто написать упрощенную версию этогосам.Для примера взгляните на этот SO-ответ .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...