2009-07-11 5 views
52

Является ли sizeof (enum) == sizeof (int), всегда?Является ли sizeof (enum) == sizeof (int), всегда?

  • Или это зависит от компилятора?
  • Неправильно ли говорить, что компилятор оптимизирован для длины слов (выравнивание по памяти), т. Е. Y int является размером слова в конкретном компиляторе? Означает ли это, что нет штрафа за обработку, если я использую перечисления, поскольку они будут выровнены по слову?
  • Не лучше, если я поместил все коды возврата в перечисление, так как я, очевидно, не беспокоюсь о его значениях, а только имена при проверке типов возврата. Если это так, то #DEFINE лучше, так как это спасет память.

Что такое обычная практика? Если мне нужно переносить эти типы возвращаемых данных по сети, и некоторая обработка должна быть выполнена на другом конце, что бы вы предпочли перечислять/# define/const ints.

EDIT - просто проверка на сеть, поскольку complier не символически связывают макросы, как люди отлаживают тогда, сравнивают целочисленное значение с файлом заголовка?

С ответами -Я Добавив эту строку ниже, как мне нужно clarifications-

«Так что определяется реализацией, и SizeOf (перечисление) может быть равна SizeOf (Char) , то есть 1. "

  • Не означает ли это, что компилятор проверяет для диапазона значений в перечислениях, а затем назначить память. Я так не думаю, конечно, я не знаю. Может кто-нибудь, пожалуйста, объясните мне, что такое «может быть».
+0

Проверил: http://stackoverflow.com/ вопросы/366017/what-is-the-size-of-an-enum-in-c И это: http://bytes.com/groups/cpp/135139-sizeof-en um-sizeof-int – Macarse

+0

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

+0

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

ответ

31

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

enum X { A, B }; 

// A has type int 
assert(sizeof(A) == sizeof(int)); 

// some integer type. Maybe even int. This is 
// implementation defined. 
assert(sizeof(enum X) == sizeof(some_integer_type)); 

Обратите внимание, что «некоторое целое число типа» в C99 может также включать в себя расширенные типы целочисленных (которые реализации, однако, к документу, если он обеспечивает их). Тип перечисления - это некоторый тип, который может хранить значение любого перечислителя (A и B в этом случае).

Я не думаю, что в использовании перечислений есть какие-либо штрафы. Перечислители также являются неотъемлемыми постоянными выражениями (поэтому вы можете использовать его для инициализации статических или переменных области видимости файла, например), и я предпочитаю их макросам, когда это возможно.

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

Я бы просто использовал тип, который может хранить значения перечислителя (я должен знать грубый диапазон значений заранее), отбрасывать на него и отправлять его по сети. Предпочтительно тип должен иметь фиксированную ширину, например int32_t, поэтому это не приводит к конфликтам при использовании различных машин. Или я напечатаю номер и сканирую его с другой стороны, что избавится от некоторых из этих проблем.


Ответ Редактирование

Ну, компилятор не обязан использовать любой размер. Легко видеть, что знак значений имеет значение - беззнаковые типы могут иметь значительное повышение производительности в некоторых вычислениях. Ниже поведение GCC 4.4.0 на моей коробке

int main(void) { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned int" 
    unsigned int *p = &a; 
} 

Но если вы назначаете -1, то GCC выбирает использовать int как тип, который X совместим с

int main(void) { 
    enum X { A = -1 }; 
    enum X a; // X compatible with "int" 
    int *p = &a; 
} 

Использование опции --short-enums GCC, что делает его самым маленьким типом, все еще поддерживающим все значения.

int main() { 
    enum X { A = 0 }; 
    enum X a; // X compatible with "unsigned char" 
    unsigned char *p = &a; 
} 
+0

Теперь я думаю, вместо того, чтобы хранить каждую команду в переменной unsigned char и приравнивать ее к значению, я должен хранить ее в #define, как это всегда делалось. Перечислениями будут проблемы с байтом. Я думаю, теперь я понимаю, почему #define всегда использовались для кодов ошибок, имен состояний, команд ... и т. Д. –

+9

Не совсем верно, что нет разницы между перечислениями и #defines: как вы сказали, для #defines компилятор даже не видит начальный токен, поскольку он подставляется реальным значением препроцессором. Компилятор действительно видит перечисления, и если вы скомпилируете код с помощью отладочных символов, отладчик покажет вам перечисленные метки вместо их значения, что значительно облегчит отладку. – Metiu

19

C99, 6.7.2.2p4 говорит

Каждый перечисляемого типа должен быть совместим с полукокса, подписанную целочисленный тип, или без знака целочисленный тип. Выбор типа определяется реализацией, 108), но должен представлять значения всех членов перечисления . [...]

Сноска 108 добавляет

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

Так что определяется реализацией, и SizeOf (перечисление) может быть равна SizeOf (Char), т.е. 1.

В размер они выбрали какой-то небольшой диапазон целых чисел, есть всегда пенальти. Если вы сделаете это маленьким в памяти, вероятно, будет штраф за обработку; если вы сделаете его больше, есть космический штраф. Это компромисс во времени.

Коды ошибок, как правило, #defines, поскольку они должны быть расширяемыми: разные библиотеки могут добавлять новые коды ошибок.Вы не можете сделать это с перечислениями.

+0

Не означает ли это, что complier проверяет диапазон значений в перечислениях, а затем присваивает память. Я так не думаю, конечно, я не знаю :). Может ли кто-нибудь объяснить, что может быть «может быть» –

+0

«Компилятор делает» - это бесполезное утверждение. В мире много компиляторов, а некоторые делают это в одну сторону, а другие делают это по-другому (даже на одном и том же оборудовании). Если вы хотите знать, что делает конкретный компилятор, вы должны назвать компилятор (включая версию и целевой процессор и операционную систему). Вполне возможно, что * ваш * компилятор всегда использует int для перечислений. –

+0

Второй ответ [здесь] (http://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c) дает другую версию того же стандарта, где говорится об этом должен быть совместим с 'int'. Является ли его версия устаревшей (он ссылается на черновик) или ваш? – Norswap

13

ли SizeOf (перечисление) == SizeOf (INT), всегда

Стандарт ANSI C говорит:

Каждый перечислимого типа, должны быть совместимы с полукокса, знаковый целочисленный тип или целочисленный тип без знака. Выбор типа определяется реализацией. (6.7.2.2 Указатели)

Таким образом, я бы принял это как означающий «нет».

Если это так, то #DEFINE лучше, так как это спасет память.

Каким образом использование определяет сохранение памяти с использованием перечисления?Перечисление - это всего лишь тип, который позволяет предоставить дополнительную информацию компилятору. В фактическом конечном исполняемом файле он просто превращается в целое число, так же как препроцессор преобразует макрос, созданный с помощью #define в его значение.

Что такое обычная практика. I, если мне придется переносить эти типы возврата по сети, и некоторая обработка должна выполняться на другом конце

Если вы планируете переносить значения по сети и обрабатывать их на другом конце, вы должны определить протокол. Решите размер в битах каждого типа, endianess (в каком порядке байты) и убедитесь, что вы придерживаетесь этого как в клиенте, так и в коде сервера. Также не просто предполагайте, что, поскольку это происходит, вы правы. Просто может быть, что endianess, например, на ваших выбранных клиентских и серверных платформах, подходит, но это может быть не всегда так.

+0

Да, это проблема, я передаю некоторое значение, которое будет использоваться в качестве команды по сети, и я хочу сделать как можно более эффективным и надежным, т. Е. Нужно знать, что использовать для команды #defines или enums, диапазон команды должны состоять не более чем из 20 команд, поэтому в соответствии со всеми ограничениями символов. Я думаю, что я опубликую его как новый вопрос, я бы получил лучший ответ. –

+1

Проще всего было бы просто использовать unsigned char. Вам не нужно беспокоиться о endianess или кодировании таким образом. – IRBMe

+0

Возможно, вы могли бы добавить ссылку на [Должен ли я использовать cstdint?] (Https://stackoverflow.com/q/6144682/2932052) для сетевого раздела – Wolf

3

В некоторых компиляторах размер перечисления зависит от количества записей в Enum. (менее 255 Entrys => Byte, более 255 Entrys int) Но это зависит от компилятора и настроек компилятора.

+0

, так или иначе я могу это сделать. Приятная благодарность. –

+0

Из-за этих проблем в нашем проекте (мы должны использовать реально старый компилятор C) мы решили не использовать перечисление. Но чтобы определить все с #define – nuriaion

4

No.

Пример: The CodeSourcery compiler

При определении перечисления, как это:

enum MyEnum1 { 
A=1, 
B=2, 
C=3 
}; 
// will have the sizeof 1 (fits in a char) 

enum MyEnum1 { 
A=1, 
B=2, 
C=3, 
D=400 
}; 
// will have the sizeof 2 (doesn't fit in a char) 

Details из их списка рассылки

+0

, если это так, то это удивительно. –

+3

это неправда .... это зависит от реализации .... оба кода дают результат как 4 на моей системе. Платформа - Ubuntu 10.04 (32-разрядная), gcc-компилятор –

+0

Неплохой пример, но обе ссылки http: // www.codesourcery.com/sgpp (1-й) и http://www.codesourcery.com/archives/arm-gnu/msg02684.html (2nd) нарушены. (надеясь на обновление ремонта.) – Wolf

Смежные вопросы