Вопрос по c-preprocessor, enums, const, c – Всегда ли sizeof (enum) == sizeof (int)?

57

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

Or is it compiler dependent? Is it wrong to say, as compiler are optimized for word lengths (memory alignment) ie y int is the word-size on a particular compiler? Does it means that there is no processing penalty if I use enums, as they would be word aligned? Is it not better if I put all the return codes in an enum, as i clearly do not worry about the values it get, only the names while checking the return types. If this is the case wont #DEFINE be better as it would save memory.

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

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

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

"So it is implementation-defined, and sizeof(enum) might be equal to sizeof(char), i.e. 1."

Does it not mean that compiler checks for the range of values in enums, and then assign memory. I don't think so, of course I don't know. Can someone please explain me what is "might be".
Возможный дубликатWhat is the size of an enum in C? underscore_d
Благодаря всему, я изучаю несколько разумных сомнений, которые, я думаю, несомненно помогут улучшить концепцию. Vivek Sharma
Проверьте:stackoverflow.com/questions/366017/…  И это:bytes.com/groups/cpp/135139-sizeof-enum-sizeof-int Macarse
В сети на каком-то форуме я думал, что enum должен быть настолько маленьким, насколько это необходимо для хранения всех его значений, в данном случае 1 байт. & Quot; Это правда. Vivek Sharma
я нашел ответы от "nuriaion" и «Лулиан Себаниу»; отношение к части вопроса. Любой ps комментирует правильность. Vivek Sharma

Ваш Ответ

5   ответов
34

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

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Таким образом, он не вступает в конфликты, когда задействованы разные машины. Или я бы напечатал номер и отсканировал его на другой стороне, что избавляет от некоторых из этих проблем.


Response to Edit

Ну, компилятор не обязан использовать любой размер. Легко видеть, что знак значений имеет значение - неподписанные типы могут иметь значительное повышение производительности в некоторых вычислениях. Ниже приведено поведение GCC4.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;
}
Теперь я думаю, что вместо того, чтобы хранить каждую команду в переменной unsigned char и приравнивать ее к значению, я буду хранить ее в #define, как это всегда было сделано. Перечисления столкнутся с проблемами порядка байтов. Теперь я понимаю, почему #define всегда использовался для кодов ошибок, имен состояний, команд ... и т. Д. Vivek Sharma
Не совсем верно, что нет никаких различий между перечислениями и #defines: как вы сказали для #defines, компилятор даже не видит начальный токен, поскольку он заменен препроцессором на реальное значение. Хотя компилятор видит перечисления, и если вы скомпилируете код с символами отладки, отладчик покажет вам перечисляемые метки вместо их значения, что значительно облегчает отладку.
Все эти разговоры о # define ... Если кто-то еще читает это, возьмите у гуру, что последнее, что вы хотите сделать, это использовать # define в C ++ для констант / перечислений. Я не добавляю, как и что еще использовать в комментарии, но это не # define.
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)

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

если это так, то это круто. Vivek Sharma
Неплохой пример, но обе ссылкиcodesourcery.com/sgpp (1-е) иcodesourcery.com/archives/arm-gnu/msg02684.html (2-й) сломаны. (в надежде на обновление ремонта.)
это не соответствует действительности ... это зависит от реализации ... оба кода выдают вывод как 4 в моей системе. Платформа - Ubuntu 10.04 (32-разрядная версия), компилятор gcc
13

Is the sizeof(enum) == sizeof(int), always

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

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined. (6.7.2.2 Enumerationspecifiers)

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

If this is the case wont #DEFINE be better as it would save memory.

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

What is the usual practise. I if i have to transport these return types over a network and some processing has to be done at the other end

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

да, это проблема, у меня есть передача некоторого значения для использования в качестве команды по сети, и я хочу сделать его максимально эффективным и надежным, т. е. мне нужны мнения, что использовать для команды #defines или enums, диапазон команд должно быть не более 20 команд, поэтому по всем в символьном пределе. Я думаю, что я опубликую это как новый вопрос, я получил бы лучший ответ. Vivek Sharma
может быть, вы могли бы добавить ссылку наShould I use cstdint? для раздела сети
Проще всего было бы просто использовать неподписанный символ. Вам не нужно беспокоиться о последовательности или кодировании таким образом.
19

C99, 6.7.2.2p4 говорит

Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,108) but shall be capable of representing the values of all the members of the enumeration. [...]

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

An implementation may delay the choice of which integer type until all enumeration constants have been seen.

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

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

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

@ Norswap Я думаю, что ответ является неправильным толкованием (того же) стандарта.
Второй ответhere дать другую версию того же стандарта, где говорится, что он должен быть совместим сint, Его версия устарела (он ссылается на черновик) или ваша?
& quot; Компилятор делает & quot; это бесполезное утверждение. В мире много компиляторов, и некоторые делают это одним способом, а другие делают это другим способом (даже на одном и том же оборудовании). Если вы хотите знать, что делает конкретный компилятор, вы должны назвать его (включая версию и целевой процессор и операционную систему). Вполне может быть, чтоyour Компилятор всегда использует int для перечислений.
Не значит ли это, что complier проверяет диапазон значений в перечислениях, а затем назначает память. Я так не думаю, конечно, я не знаю :). Могут ли некоторые показать, пожалуйста, объясните, что такое "может быть" Vivek Sharma
2

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

в любом случае я могу заставить это. Хороший вклад, хотя. Vivek Sharma
Из-за этих проблем в нашем проекте (мы должны использовать очень старый компилятор C) мы решили не использовать enum. Но определить все с помощью #define
Речь идет не о количестве членов перечислителя, а о диапазоне значений, которые они представляют. Я мог бы иметьenum содержащий 2 члена:{apples = 0, oranges = 1000}, Как вы думаете, компилятор может вписать их в любойchar (& Quot; Байт & Quot;)? Не без сопоставления между значениями перечислителя и базовыми значениями, которого, очевидно, не существует: это было бы кошмаром для реализации, производительности и использования.enum на самом деле это просто способ иметь некоторый контекстно-зависимый целочисленный тип, но иметь возможность ссылаться на его члены с помощью текстовых идентификаторов; члены хранятся как их числовые значения.

Похожие вопросы