Имеет ли определение типа enum тяжелый отпечаток памяти?

Я работаю со встроенным устройством с 32 КБ памяти, пишу на простом C, используя IAR EWARM v6.30.

Чтобы сделать код более читаемым, я хотел бы определить некоторые типы перечислений, например, что-то вроде

{RIGHT_BUTTON, CENTER_BUTTON, LEFT_BUTTON}

вместо использования значений 0, 1, 2, но я боюсь, что это займет дополнительную память, которой и без того мало.

Итак, у меня есть 2 вопроса: 1) Могу ли я заставить enum иметь тип short или byte вместо int? 2) Каков точный отпечаток памяти для определения типа перечисления?


person Flot2011    schedule 04.04.2012    source источник


Ответы (4)


В полностью совместимом ISO C размер и тип константы перечисления такие же, как signed int. Некоторые компиляторы встроенных систем намеренно не соблюдают это как оптимизацию или расширение.

В ISO C++ «базовый тип перечисления — это целочисленный тип, который может представлять все значения перечислителя, определенные в перечислении.», поэтому компилятор может использовать наименьший возможный тип, и большинство из них , но не обязаны это делать.

В вашем случае (IAR EWARM) в инструкции четко написано:

введите здесь описание изображения

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

person Clifford    schedule 04.04.2012
comment
: ОК, так что вы все равно хотите объяснения. Вот оно: я вообще не работаю с этим компилятором, я работаю с VS2003, и мой код позже перекомпилирован на машине клиента, потому что клиент не хочет покупать для меня лицензию :-( У меня было срок действия пробной версии истек, и я удалил ее. Поскольку я не был уверен, какую именно версию IAR клиент в конечном итоге будет использовать, я подумал, что лучше задать общий вопрос. Но на самом деле вы правы, я немного поленился. . Спасибо за ответ. - person Flot2011; 05.04.2012
comment
Насколько я помню (но могу ошибаться), оценочная лицензия с истекшим сроком действия позволяет компилировать, но не связывать или загружать код в цель. Если это так, возможно, было бы полезно сохранить установку для проверки того, что код по крайней мере скомпилируется, и для доступа к документации. - person Clifford; 05.04.2012
comment
Я не верю, что это правильно. C11 6.7.2.2 утверждает, что "The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.", но также и "Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration." - person Lundin; 05.04.2012
comment
Для вашего примера из IAR это будет означать, что Spade1, Spade2 и т. д. гарантированно будут (подписанными) int, но переменная типа enum Cards может быть char, signed int или unsigned int. - person Lundin; 05.04.2012
comment
C11 не имеет значения, если вы не используете компилятор, который его реализует, что в настоящее время делают очень немногие. Рассматриваемый компилятор соответствует стандарту ISO/IEC 9899:1999 (согласно документации). Более того, стандарт ISO может говорить то, что ему нравится; Текст, который я разместил, на самом деле является скриншотом руководства IAR - я его не выдумывал! - person Clifford; 05.04.2012
comment
Но что, если я хочу использовать --enum-as-unsigned-int? Это очень полезно, если я использую перечисления в качестве битовых флагов, поскольку битовые операции не рекомендуются и не совместимы с MISRA:2004 для типа int. - person lkanab; 03.08.2015
comment
@lkanab: использование перечислений для битовых флагов, вероятно, плохая идея - например, если вы объедините два флага с |, вы получите целое число, которое больше не является значением перечисления (если только вы не определите все возможные комбинации!), и, конечно же, больше не имеет типа перечисления. Вместо этого используйте битовые поля const, #define или struct по мере необходимости. В любом случае - вы задали вопрос в комментарии к едва связанной проблеме - опубликуйте новый вопрос, а не комментируйте ответы трехлетней давности. Комментируя этот ответ, вы спрашиваете только меня, когда вы могли бы спрашивать всех или ТАК! - person Clifford; 03.08.2015

Если вам действительно нужно уменьшить размер данных до char, вы всегда можете использовать набор #define постоянных значений для представления enum состояний и использовать только эти значения в своих заданиях и тестах.

person uɐɪ    schedule 04.04.2012

Для соответствующего компилятора перечисляемая константа всегда имеет тип int (эквивалентно signed int). Но такие константы обычно не хранятся в памяти, поэтому их тип, вероятно, не окажет большого влияния на требования к памяти.

Объявленный объект перечисляемого типа имеет сам перечисляемый тип, который совместим с char или с некоторым целочисленным типом со знаком или без знака. Выбор типа определяется реализацией (т. е. компилятор может выбрать, но он должен задокументировать, как он делает выбор); единственное требование состоит в том, что тип должен быть способен хранить значения всех констант.

По общему признанию, странно, что константы имеют тип int, а не перечисляемый тип, но именно так определен язык (причины исторические, а в C++ другие правила).

Например, учитывая:

enum foo { x, y, z };
enum foo obj;
obj = z;

выражение z имеет тип int и имеет значение 2 (точно так же, как десятичная константа 2), но объект obj имеет тип enum foo и может иметь размер всего один байт, в зависимости от компилятора. Назначение obj = z; включает неявное преобразование из int в enum foo (для этого преобразования может потребоваться или не потребоваться дополнительный код).

Некоторые компиляторы могут предоставлять нестандартный способ указания типа, который будет выбран для перечисляемого типа. Некоторые могут даже каким-то образом нарушать стандарт. Обратитесь к документации вашего компилятора, распечатайте значение sizeof (enum foo) и, при необходимости, проверьте сгенерированный код.

Вполне вероятно, что ваш компилятор будет принимать разумные решения в рамках ограничений, налагаемых языком. Для компилятора, предназначенного для встраиваемых систем с недостаточным объемом памяти, особенно вероятно, что компилятор либо выберет небольшой тип, либо позволит вам указать его. Обратитесь к документации вашего компилятора.

Как предполагает ответ Яна, если вы хотите самостоятельно контролировать использование памяти, вы можете использовать объекты char или unsigned char. Однако вы все равно можете использовать определение enum для определения констант. Например:

enum { x, y, z }; // No tag, so you can't declare objects of this type
typedef unsigned char foo; // an enum_foo object is guaranteed to be 1 byte
foo obj = z;

Ссылка: раздел 6.7.2.2 стандарта C. Ссылка на 1,7-мегабайтный PDF-файл последнего проекта стандарта ISO C 2011 года; этот конкретный раздел существенно не изменился с 1989 года.

person Keith Thompson    schedule 04.04.2012
comment
Это правильный ответ для C. Я могу убедиться, что текст стандарта не изменился между черновиком C11 и официальным стандартом C11. - person Lundin; 05.04.2012

Компилятор ANSI C всегда будет представлять перечисление как int для представления переменных типа enum.

http://en.wikipedia.org/wiki/Enumerated_type#C_and_syntactically_similar_languages

Одним из вариантов использования int в вашей программе было бы использование их для определения значений, но преобразование в char при фактическом использовании.

char value = (char)Buttons.RIGHT_BUTTON;
person Eric J.    schedule 04.04.2012
comment
Да, я знаю это, я просто надеялся, что есть какой-то переключатель компилятора, чтобы изменить это поведение по умолчанию. - person Flot2011; 04.04.2012
comment
@Flot2011: зависит от вашего компилятора. Какой компилятор вы используете? - person Eric J.; 04.04.2012