Всегда ли sizeof (enum) == sizeof (int)? - PullRequest
57 голосов
/ 11 июля 2009

Всегда ли sizeof (enum) == sizeof (int)?

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

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

РЕДАКТИРОВАТЬ - Просто проверять в сети, так как компилятор символически не связывает макросы, как тогда люди отлаживают, сравнивают целочисленное значение с файлом заголовка?

Из ответов - я добавляю эту строку ниже, поскольку мне нужны пояснения -

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

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

Ответы [ 5 ]

34 голосов
/ 11 июля 2009

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

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;
}
19 голосов
/ 11 июля 2009

C99, 6.7.2.2p4 говорит

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

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

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

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

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

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

13 голосов
/ 11 июля 2009

Это sizeof (enum) == sizeof (int), всегда

Стандарт ANSI C гласит:

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

Так что я бы сказал, что это означает нет.

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

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

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

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

4 голосов
/ 11 июля 2009

номер

Пример: Компилятор CodeSourcery

Когда вы определяете перечисление следующим образом:

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)

Подробности из списка рассылки

2 голосов
/ 11 июля 2009

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

...