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 байт для хранения и, с другой стороны, для выполнения операций с использованием наиболее подходящего перечисления, определенного так, как вам нравится).

Другие вопросы по тегам