19

В С есть тип long. Согласно: Wiki c-types он занимет в памяти 4 байта, да и диапазон значений у него такой же как и у int. Тогда зачем он нужен?

Выписка из wiki:

int:

Основной тип целого числа со знаком. Может содержать числа в диапазоне [−32767, +32767]. range;[3][4] Таким образом, это по крайней мере 16 бит (2 байта). На практике, во всех современных компиляторах имеет размер в 4 байта и диапазон [-2147483648, +2147483647]

long:

Тип длинного целого числа со знаком. Может содержать числа, как минимум, в диапазоне [−2 147 483 647, +2 147 483 647].[3][4] Таким образом, это по крайней мере 32 бита (4 байта).

demonplus
  • 878
Alerr
  • 2,606
  • 8
    На практике long чаще всего вдвое больше int. Стандарт гарантирует, что не меньше, но не запрещает быть больше. – free_ze Feb 14 '17 at 12:10
  • 2
    @free_ze "чаще всего" - это когда? :-) – Pavel Mayorov Feb 14 '17 at 12:11
  • @PavelMayorov очевидно, что на распространенных пользовательских платформах, которые средний по больнице Вася встречает чаще всего) – free_ze Feb 14 '17 at 12:13
  • Выходит его создали чтобы писать код можно было оптимальнее, когда на устройстве мало места и тебе очень важен размер переменных. То есть это с древних времен перешло к нам? – Alerr Feb 14 '17 at 12:20
  • @free_ze это какие - распространенные пользовательские? – Pavel Mayorov Feb 14 '17 at 12:23
  • 2
    @PavelMayorov Вас научить гуглить рейтинги?) – free_ze Feb 14 '17 at 12:24
  • @free_ze нет. Надо просто перечислить конкретные пары из платформы и компилятора. – Pavel Mayorov Feb 14 '17 at 12:25
  • 1
    @PavelMayorov Никто не будет против, если вы дополните мой комментарий своими примерами. К чему же этот флуд? – free_ze Feb 14 '17 at 12:46
  • Скорее, зачем нужен int, когда есть short и long – vp_arth Feb 14 '17 at 12:48
  • 2
    @free_ze, очевидно, что на распространенных пользовательских платформах, которые средний по больнице Вася встречает чаще всего -- не, не на распространенных пользовательских, а на правильных (а наиболее распространенная винда к ним не относится) – avp Feb 14 '17 at 13:11
  • @avp не могли бы вы подробнее раскрыть тему этих правил? И почему винды в этом случае неправильные? – free_ze Feb 14 '17 at 14:14
  • 1
    @free_ze, а что тут раскрывать? *nix -- правильные -). – avp Feb 14 '17 at 17:22
  • Термин "платформа" в терминологии языка С/С++ является синонимом терминов "реализация"/"компилятор". Размеры типов физически определяются только компилятором, и могут, при желании, выбираться с полным игнорированием параметров хардверной платформы. Игнорировать параметры машины в С/С++ не принято, но никаких формальных преград этому нет. – AnT stands with Russia Feb 14 '17 at 18:17
  • 1
    @avp ...а бог сидит на небе, верно?) – free_ze Feb 15 '17 at 06:45
  • 1
    @free_ze, будучи агностиком, вполне могу это допустить. / Что же касается винды (я не ошибся, вас именно это мучает?), то не опускаясь (поднимаясь?) до глубин архитектуры систем, пожалуйста, один небольшой пример -- программа, запущенная из cmd получает аргументы командной строки в кодировке cp1251, а stdin с терминалом в cp866. – avp Feb 15 '17 at 09:58

4 Answers4

19

Размеры типов int и long не регламентированы Стандартом языка. Но регламентировано отношение их размеров, т.е. sizeof(int) <= sizeof(long).

На текущий момент можно сказать, что размер long зависит как от разрядности процессора, так и от используемой ОС. Например, для Linux и MacOS он будет 8 байт для 64bit архитектур, и 4 байта для 32bit архитектур. В Windows размер будет 4 байта, независимо от разрядности архитектуры.

Например, в Стандарте С++ даже встречается такой пример:

static_assert(sizeof(long) >= 8, "64-bit code generation required for this library.");

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

void f(int) {}
void f(long) {}
f(42); // int
f(42L); // long

Также не стоит забывать, что данные типы имеют разный ранг (integer conversion rank), что влияет на правила преобразования целочисленных типов.

Уточнение по поводу размеров long после комментариев @AnT со страницы cygwin:

While the Mingw and Microsoft compilers use the LLP64 data model, Cygwin compilers use the LP64 data model, just like Linux. This affects the size of the type long. In the LLP64 model preferred by Microsoft, sizeof(long) is 4. This applies for the related Win32 types like LONG, ULONG, DWORD, etc., too.

In the LP64 model used by Cygwin, sizeof(long) is 8, just like the size of pointers or the types size_t/ssize_t. This simplifies porting Linux applications to 64 bit Cygwin, but it requires due diligence when calling Windows functions taking LONG, ULONG, DWORD, or any other equivalent type. This is especially important in conjunction with pointers.

αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119
  • 1
    Ответ вводит в заблуждение. Размер целого С/С++ типа не зависит от используемой ОС вообще никак. Размер типа зависит только от компилятора и больше ни от чего. Компилятор, разумеется, в вопросах выбора размера типа будет руководствоваться сображениями эффективности, что привнесет сюда и учтение разрядности процессора. Так что разрядность процессора косвенно/опосредованно влияет. Точнее, не "влияет", а скажем, "снисходительно/необязательно учитывается" при принятии таких решений. Кроме компилятора на размер типа не влияет больше ничто. – AnT stands with Russia Feb 14 '17 at 18:11
  • @AnT мы же не о сферических конях в вакууме тут беседуем. Да и не сам я это придумал, и даже ссылку добавил. Плюс пример из вполне настоящего Стандарта. – αλεχολυτ Feb 14 '17 at 18:27
  • 1
    При чем здесь сферические кони? Нет никаких причин типу long быть 4 байта "на Windows". Более того, это утверждение соврешено не верно: в компиляторе MSVC на Windows long - 4 байта, в компиляторе GCC на Windows long - 8 байт. Так что Windows тут никакой роли не играет. Это вопрос решения авторов компилятора, котрое зависит от соврешенно иных причин. Да и тот факт, что в 64-битном мире тип int не стал 64-битным (как рекомендуют стандарты С и С++) практически ни в одном компиляторе говорит о том, что вопросы обратной совместимости играют бОльшую роль, чем разрядность процессора. – AnT stands with Russia Feb 14 '17 at 18:33
  • @AnT "в компиляторе GCC на Windows long - 8 байт." Я вот поставил MinGW-w64 и тестовый код говорит, что sizeof(long) == 4 для 64bit окружения. ОС Win7. – αλεχολυτ Feb 15 '17 at 13:12
  • А я вот поставил Cygwin и тестовый код говорит, что sizeof(long) == 8. Ваш MinGW, очевидно, эмулирует поведение MSVC для совместимости с его билиотеками. – AnT stands with Russia Feb 15 '17 at 15:11
17

Процессоры развивались постепенно все более расширяя емкость регистров. Например, ранее в DOS тип int соответствовал 16 разрядному целочисленному значению, так как на IBM-совместимых компьютеров регистры были 16-разрядными. Например, регистр AX является 16 разрядным, а его подрегистры AL и AH имели разрядность равную 8 битам. До этого вообще регистры процессоров были 8 разрядными.

Если выполнить, допустим, умножение двух объектов 16-разрядного типа int, то для хранения результата нужно использовать два регистра как, например, регистры AX и DX. Для этого результата уже нужно вводить новый целочисленный тип. И такой тип был введен. Это тип long .

Затем появились 64-разрядные процессоры. Необходимо различать 16-разрядные целые числа, 32-разрядные целые числа и 64- разрядные целые числа. Поэтому был введен дополнительный целый тип Long long. Имейте в виду, что нужно было сохранять обратную совместимость с целыми типами, введенными ранее для процессоров с меньшей разрядностью.

Поэтому в стандарте C принято, что

sizeof( short ) <= sizeof( int )
sizeof( int ) <= sizeof( long )
sizeof( long ) <= sizeof( long long )

У разработчиков компиляторов есть свобода выбора, какая разрядность будет у типа long и других целочисленных типов. Например, разрядность типа long может составлять не `32 бита, а 64 бита.

Чтобы программы были переносимы, возникла необходимость вводить новые типы со строго указанной разрядностью такие, как, например, int_least32_t или int32_t.

На одних 64-битовых платформах тип long и тип long long могут иметь 64-битовуж разрядность. На других 64-битовых платформах тип long может быть 32-битовым и тип int также может быть 32-битовым, а тип long long - 64 битовым.

Тем не менее ранг типа long long больше ранга типа long, а тип long в свою очередь имеет ранг выше, чем тип int.

На этом основываются правила преобразования типов в выражениях. Например, если тип long и тип int имеют разрядность равную 32 битам, то в следующем фрагменте кода

long x = 0;
unsigned int y = 0;

x + y;

тип выражения x + y имеет тип unsigned long.

В связи с этим имеются некоторые курьезы, связанные с такими преобразованиями особенно при выборе перегруженной функции в C++.

Один из таких примеров описан в следующей теме, где ближе к ее концу (можно быстро найти это сообщение по ключевому слову int64_t) описывается один из таких курьезов, связанных с вызовом перегруженной функции, у которой параметр имеет тип std::int64_t, который, как оказалось, является не алиасом типа long long int, а алиасом типа long int, который на данной платформе является 64-битовым.

6

Тип long не "занимает в памяти 4 байта". Он занимает как минимум 32 бита, т.е. имеет диапазон как минимум [−2147483647, +2147483647]. А сверху его размер не ограничен.

Тип int занимает как минимум 16 бит, ибо имеет диапазон как минимум [−32767, +32767] (как вы сами заметили).

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

В языке С++ система целочисленных типов обладает тем свойством, что

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

т.е. вполне возможно что размеры (и диапазоны) этих типов все будут различными.

В языке С, по каким-то историческим причинам, это соотношение определяется как

диапазон(signed char) ⊆ диапазон(short) ⊆ диапазон(int) ⊆ диапазон(long) ⊆ диапазон(long long)

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

То, что у вас на какой то платформе тип long совпал по представлению с типом int является лишь особенностью вашей платформы.

  • short может быть 1 байт? – αλεχολυτ Feb 14 '17 at 17:22
  • 4
    @alexolut: Разумеется, может быть. Но еще раз: речь идет о C-байте, то есть об байте типа char. А этот C-байт имеет право содержать сколько угодно бит. Например, на платформах для микроконтроллеров Texas Instruments TMS320C28x CHAR_BIT == 16 и sizeof(char) == sizeof(short) == sizeof(int) == 1. То есть и short и даже int занимают 1 байт. Только это 16-битный байт. См. например https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/21671 – AnT stands with Russia Feb 14 '17 at 17:48
  • 1
    Интересно, а есть ли сейчас архитектуры, где размеры всех упомянутых стандартных типов различны? – αλεχολυτ Feb 16 '17 at 08:07
  • @alexolut, похоже RISC-V, но что из 128-бит варианта реализовано в железе, не знаю. – avp Feb 17 '17 at 10:48
  • Кол-во значений в интервале [−2147483647, +2147483647] (в открытом или закрытом) нечетное, что не стыкуется с двоичной системой счисления (в которой при любом кол-ве бит, кол-во значений всегда четное): либо одно из значений зарезервировано (запрещено), либо два значения обозначают одно число). Не могли бы вы подробнее этот момент объяснить. – Vladimir Gamalyan Feb 25 '17 at 03:32
  • @Vladimir Gamalian: [−2147483647, +2147483647] - это гарантированный интервал. Но никто не запрещает нам сделать его ассиметричным - [−2147483648, +2147483647], как это и делается в наших повседневных платформах с дополнительным кодом. В результате не надо никаких "зарезервированых значений" или "два значения обозначают одно число". – AnT stands with Russia Feb 25 '17 at 03:45
  • @AnT нет под рукой ссылки на стандарт? Листал, пока не нашел. – Vladimir Gamalyan Feb 25 '17 at 03:46
  • @Vladimir Gamalian: Сссылки про что именно? – AnT stands with Russia Feb 25 '17 at 03:47
  • @AnT где в стандарте гарантируется этот ([−2147483647, +2147483647]) интервал для long. – Vladimir Gamalyan Feb 25 '17 at 03:48
  • 1
    @Vladimir Gamalian: В разделе 3.9.1/3 стандарта С++ (С++14) говорится, что к целочисленным типам в С++ применяются все требования из раздела 5.2.4.2.1 стандарта С. А уж в 5.2.4.2.1 стандарта С сказано, что значение LONG_MIN должно быть -2147483647 или меньше, а значение LONG_MAX должно быть +2147483647 или больше. – AnT stands with Russia Feb 25 '17 at 03:59
  • @AnT то же нашел уже, спасибо большое – Vladimir Gamalyan Feb 25 '17 at 04:03
  • @AnT, "В языке С++ система целочисленных типов обладает тем свойством, что sizeof(short) <= sizeof(int)". Мне вот интересно, а возможна ли такая ситуация: и short, и int оба 32-битные; у типа short все биты участвуют в представлении значения, но у типа int только (15 + 1) бит кодируют числа, а остальные 16 являются padding bits? – wololo Mar 08 '18 at 21:43
4

Язык C предлагает Вам множество типов. В частности гарантированно, что int не больше long. А long не больше long long. Вы выбираете по своим нуждам и удобству.

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

На разных архитектурах ЭВМ разные размеры регистров процессора, но соотношение размеров типов сохраняется.

Простыми словами: часто использовали int в программах, поэтому его вытянули под размер 4 байта на PC, что соответствует регистру процессора x32. long не стали вытягивать до 8 байт, потому что на x32 потребуется две команды процессору вместо одной. Но не удалять же long, ведь его используют какие-то программы.