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

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

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

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

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

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

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

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

Ответ 1

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

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;
}

Ответ 2

C99, 6.7.2.2p4 говорит

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

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

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

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

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

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

Ответ 3

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

В стандарте ANSI C говорится:

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

Таким образом, я хотел бы, чтобы это означало "нет".

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

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

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

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

Ответ 4

Нет.

Пример: Компилятор 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)

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

Ответ 5

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