8-битное перечисление, в C
Я должен хранить инструкции, команды, которые я буду получать через последовательный порт. Команды будут длиной 8 бит.
Мне нужно сохранить прозрачность между именем команды и ее значением. Чтобы избежать необходимости переводить 8-битное число, полученное последовательно, в любой тип.
Я хотел бы использовать перечисления для работы с ними в моем коде. Только перечисление соответствует 16-разрядному целому числу на этой платформе.
Платформа представляет собой микроконтроллер AVR ATmega169V на демонстрационной плате Butterfly. Это 8-битная система с некоторой ограниченной поддержкой 16-битных операций. Это не быстрая система и имеет около 1 КБ ОЗУ. Он не имеет такой роскоши, как файловый ввод-вывод или операционные системы.
Таким образом, какие-либо предложения относительно того, какой тип я должен использовать для хранения 8-битных команд?
Должно быть что-то лучше, чем массивный заголовок #defines.
6 ответов
gcc
"s -fshort-enums
может быть полезно:
Выделите типу enum только столько байтов, сколько необходимо для объявленного диапазона возможных значений. В частности, тип "enum" будет эквивалентен наименьшему целочисленному типу, который имеет достаточно места.
На самом деле, вот страница с большим количеством актуальной информации. Я надеюсь, что вы встретите много переключателей GCC, о которых вы даже не подозревали.;)
Вы пытаетесь решить проблему, которой не существует.
Ваш вопрос помечен как C. В языке C перечисляемые типы в контексте значений полностью совместимы с целочисленными типами и ведут себя так же, как и другие целочисленные типы. При использовании в выражениях они подвергаются точно таким же интегральным преобразованиям, что и другие интегральные типы. Приняв это во внимание, вы должны понимать, что если вы хотите хранить значения, описываемые константами перечисления, в 8-битном интегральном типе, все, что вам нужно сделать, это выбрать подходящий универсальный 8-битный интегральный тип (скажем, int8_t
) и используйте его вместо типа enum. Вы абсолютно ничего не потеряете, сохранив значения констант enum в объекте типа int8_t
(в отличие от объекта, явно объявленного с типом enum).
Проблема, которую вы описываете, существует в C++, где типы enum значительно отделены от других целочисленных типов. В C++ использование целочисленного типа вместо типа enum для экономии памяти более сложно (хотя и возможно). Но не в Си, где это не требует никаких дополнительных усилий.
Я не понимаю, почему enum не сработает. Сравнения и присваивания из перечисления должны хорошо работать с расширением по умолчанию. Просто будьте осторожны, чтобы ваши 8-битные значения были подписаны правильно (я думаю, вы захотите расширение без знака).
Таким образом, вы получите 16-битное сравнение, я надеюсь, что это не будет проблемой для производительности (не должно быть, особенно если ваш процессор 16-битный, как кажется).
Компилятор Microsoft C позволяет вам делать что-то вроде этого, но это расширение (стандартно в C++0x):
enum Foo : unsigned char {
blah = 0,
blargh = 1
};
Поскольку вы пометили GCC, я не совсем уверен, возможно ли то же самое, но GCC может иметь расширение в gnu99
режим или что-то для этого. Дай вихрь.
Ответ, который важен для компилятора ARC (цитируется в Руководстве по программированию для ARC DesignWare MetaWare C / C++; раздел 11.2.9.2)
Размер перечислений Размер типа перечисления зависит от состояния переключателя *Long_enums*.
■ Если переключатель *Long_enums* выключен, тип enum сопоставляется с наименьшим из одного, двух или четырех байтов, так что все значения могут быть представлены.
■ Если переключатель *Long_enums* включен, перечисление отображается в четыре байта (в соответствии с соглашением AT&T Portable C Compiler).
Я бы порекомендовал остаться на enum в любом случае по следующим причинам:
- Это решение позволяет вам напрямую сопоставлять значения команд с тем, что ожидает ваш последовательный протокол.
- Если вы действительно используете 16-битную архитектуру, то не так много преимуществ для перехода на 8-битный тип. Подумайте об аспектах, отличных от 1 сохраненного байта памяти.
- В некоторых компиляторах я использовал фактический размер перечисления, использующий минимальное количество битов (перечисления, которые можно уместить в байтах, используют только байт, затем 16 бит, затем 32).
Во-первых, вы не должны заботиться о реальной ширине шрифта. Только если вам действительно нужен эффективный способ хранения, вы должны использовать флаги компилятора, такие как -fshort-enums на компиляторе GNU, но я не рекомендую их, если они вам действительно не нужны.
В качестве последней опции вы можете определить 'enum' как данные представления для команд и использовать преобразование в байт с помощью двух простых операций, чтобы сохранить / восстановить значение команды в / из памяти (и инкапсулировать это в одном месте). Как насчет этого? Это очень простые операции, поэтому вы можете даже встроить их (но это позволяет вам реально использовать только 1 байт для хранения и, с другой стороны, для выполнения операций с использованием наиболее подходящего перечисления, определенного так, как вам нравится).