Имеет ли определение типа enum большой отпечаток памяти?
Я работаю со встроенным устройством, с 32K памяти, пишу на простом C, используя IAR EWARM v6.30.
Чтобы сделать код более читабельным, я бы хотел определить некоторые типы перечислений, например, что-то вроде
{RIGHT_BUTTON, CENTER_BUTTON, LEFT_BUTTON}
вместо использования значений 0, 1, 2, но, боюсь, потребуется дополнительная память, которой уже мало.
Итак, у меня есть 2 вопроса: 1) Могу ли я заставить enum быть кратким или байтовым типом intead of int? 2) Каков точный отпечаток памяти определения типа enum?
4 ответа
В полностью совместимом ISO C размер и тип константы перечисления signed int
, Некоторые компиляторы встраиваемых систем сознательно не соответствуют этому как оптимизации или расширению.
В ISO C++ "Базовый тип перечисления является целочисленным типом, который может представлять все значения перечислителя, определенные в перечислении.", Поэтому компилятор может использовать наименьший возможный тип, и большинство его используют, но не обязаны делать это. так.
В вашем случае (IAR EWARM) в руководстве четко сказано:
Опция не требуется, на самом деле вам нужно использовать --enum_is_int
для принудительного поведения. Другие компиляторы могут вести себя по-разному или иметь другие расширения, прагмы или опции для управления этим. Такие вещи обычно будут определены в документации.
Для соответствующего компилятора перечисляемая константа всегда имеет тип 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 года.
Если вам действительно нужно сохранить размер данных до char
тогда вы всегда можете использовать набор #define
постоянные значения для представления enum
состояния и только когда-либо использовать эти значения в ваших заданиях и тестах.
Компилятор ANSI C всегда будет представлять перечисление как int
представлять переменные типа enum
,
http://en.wikipedia.org/wiki/Enumerated_type
Один вариант использовать int
s в вашей программе будет использовать их для определения значений, но приведение к char
когда на самом деле используется
char value = (char)Buttons.RIGHT_BUTTON;