В чем разница между int и long в C++?

Поправь меня, если я ошибаюсь,

int составляет 4 байта с диапазоном значений от -2 147 483 648 до 2 147 483 647 (2^31)
long - 4 байта с диапазоном значений от -2 147 483 648 до 2 147 483 647 (2^31)

В чем разница в C++? Могут ли они быть взаимозаменяемыми?

9 ответов

Решение

Это зависит от реализации.

Например, под Windows они одинаковы, но, например, в системах Alpha long был 64 бит, тогда как int был 32 бит. В этой статье рассматриваются правила для компилятора Intel C++ на переменных платформах. Подвести итоги:

  OS           arch           size
Windows       IA-32        4 bytes
Windows       Intel 64     4 bytes
Windows       IA-64        4 bytes
Linux         IA-32        4 bytes
Linux         Intel 64     8 bytes
Linux         IA-64        8 bytes
Mac OS X      IA-32        4 bytes
Mac OS X      Intel 64     8 bytes  

Единственная гарантия, которую вы имеете:

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

// FROM @KTC. The C++ standard also has:
sizeof(signed char)   == 1
sizeof(unsigned char) == 1

// NOTE: These size are not specified explicitly in the standard.
//       They are implied by the minimum/maximum values that MUST be supported
//       for the type. These limits are defined in limits.h
sizeof(short)     * CHAR_BIT >= 16
sizeof(int)       * CHAR_BIT >= 16
sizeof(long)      * CHAR_BIT >= 32
sizeof(long long) * CHAR_BIT >= 64
CHAR_BIT         >= 8   // Number of bits in a byte

Также см.: Есть long гарантированно будет не менее 32 бит?

При компиляции для x64 разница между int и long составляет где-то между 0 и 4 байтами, в зависимости от того, какой компилятор вы используете.

GCC использует модель LP64, что означает, что целые числа являются 32-разрядными, а длинные - 64-разрядными в 64-разрядном режиме.

Например, MSVC использует модель LLP64, что означает, что как целые, так и длинные являются 32-битными даже в 64-битном режиме.

Сама спецификация C++ (старая версия, но достаточно хорошая для этого) оставляет это открытым.

Существует четыре целых типа со знаком:signed char','short int','int', а также 'long int". В этом списке каждый тип обеспечивает как минимум столько же памяти, сколько предшествует ему в списке. Простые целые имеют натуральный размер, предложенный архитектурой среды исполнения *;

[Сноска: то есть достаточно большая, чтобы содержать любое значение в диапазоне INT_MIN и INT_MAX, как определено в заголовке <climits>, --- конец фонота]

Как указывает Кевин Хейнс, интты имеют естественный размер, предложенный средой исполнения, который должен соответствовать INT_MIN и INT_MAX.

Стандарт C89 гласит, что UINT_MAX должно быть не менее 2 ^ 16-1, USHRT_MAX 2 ^ 16-1 и ULONG_MAX 2^32-1 . Это делает подсчет битов по меньшей мере 16 для коротких и целых и 32 для длинных. Для символа char явно указывается, что он должен иметь не менее 8 бит (CHAR_BIT). C++ наследует эти правила для файла limit.h, поэтому в C++ мы предъявляем те же фундаментальные требования к этим значениям. Однако вы не должны получать из этого, что int - это как минимум 2 байта. Теоретически char, int и long могут быть равны 1 байту, и в этом случае CHAR_BIT должно быть не менее 32. Просто помните, что "байт" всегда имеет размер символа, поэтому, если символ больше, байт больше не только 8 бит.

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

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

Большинство поставщиков компиляторов предоставляют заголовочный файл, который определяет примитивные типы с размерами эксплицитных типов. Эти примитивные типы должны использоваться, когда когда-либо код может быть потенциально перенесен на другой компилятор (читайте это как ВСЕГДА в КАЖДОМ экземпляре). Например, большинство компиляторов UNIX имеют int8_t uint8_t int16_t int32_t uint32_t, Microsoft имеет INT8 UINT8 INT16 UINT16 INT32 UINT32, Я предпочитаю Borland/CodeGear's int8 uint8 int16 uint16 int32 uint32, Эти имена также дают небольшое напоминание о размере / диапазоне предполагаемого значения.

В течение многих лет я использовал явные примитивные имена типов Borland и #include следующий файл заголовка C/C++ (primitive.h), предназначенный для определения явных типов примитивов с этими именами для любого компилятора C/C++ (этот файл заголовка может на самом деле не охватывать каждый компилятор, но он охватывает несколько компиляторов, которые я использовал в Windows, UNIX и Linux, он также (пока) не определяет 64-битные типы).

#ifndef primitiveH
#define primitiveH
// Header file primitive.h
// Primitive types
// For C and/or C++
// This header file is intended to define a set of primitive types
// that will always be the same number bytes on any operating operating systems
// and/or for several popular C/C++ compiler vendors.
// Currently the type definitions cover:
// Windows (16 or 32 bit)
// Linux
// UNIX (HP/US, Solaris)
// And the following compiler vendors
// Microsoft, Borland/Imprise/CodeGear, SunStudio,  HP/UX
// (maybe GNU C/C++)
// This does not currently include 64bit primitives.
#define float64 double
#define float32 float
// Some old C++ compilers didn't have bool type
// If your compiler does not have bool then add   emulate_bool
// to your command line -D option or defined macros.
#ifdef emulate_bool
#   ifdef TVISION
#     define bool int
#     define true 1
#     define false 0
#   else
#     ifdef __BCPLUSPLUS__
      //BC++ bool type not available until 5.0
#        define BI_NO_BOOL
#        include <classlib/defs.h>
#     else
#        define bool int
#        define true 1
#        define false 0
#     endif
#  endif
#endif
#ifdef __BCPLUSPLUS__
#  include <systypes.h>
#else
#  ifdef unix
#     ifdef hpux
#        include <sys/_inttypes.h>
#     endif
#     ifdef sun
#        include <sys/int_types.h>
#     endif
#     ifdef linux
#        include <idna.h>
#     endif
#     define int8 int8_t
#     define uint8 uint8_t
#     define int16 int16_t
#     define int32 int32_t
#     define uint16 uint16_t
#     define uint32 uint32_t
#  else
#     ifdef  _MSC_VER
#        include <BaseTSD.h>
#        define int8 INT8
#        define uint8 UINT8
#        define int16 INT16
#        define int32 INT32
#        define uint16 UINT16
#        define uint32 UINT32
#     else
#        ifndef OWL6
//          OWL version 6 already defines these types
#           define int8 char
#           define uint8 unsigned char
#           ifdef __WIN32_
#              define int16 short int
#              define int32 long
#              define uint16 unsigned short int
#              define uint32 unsigned long
#           else
#              define int16 int
#              define int32 long
#              define uint16 unsigned int
#              define uint32 unsigned long
#           endif
#        endif
#      endif
#  endif
#endif
typedef int8   sint8;
typedef int16  sint16;
typedef int32  sint32;
typedef uint8  nat8;
typedef uint16 nat16;
typedef uint32 nat32;
typedef const char * cASCIIz;    // constant null terminated char array
typedef char *       ASCIIz;     // null terminated char array
#endif
//primitive.h

По большей части количество байтов и диапазон значений определяется архитектурой ЦП, а не C++. Тем не менее, C++ устанавливает минимальные требования, которые Литб объяснил правильно, и Мартин Йорк допустил только несколько ошибок.

Причина, по которой вы не можете использовать int и long взаимозаменяемо, заключается в том, что они не всегда имеют одинаковую длину. C был изобретен на PDP-11, где байт имел 8 битов, int был двумя байтами и мог обрабатываться непосредственно аппаратными инструкциями. Поскольку программистам на C часто требовалась четырехбайтовая арифметика, был изобретен long, и это было четыре байта, которые обрабатывались библиотечными функциями. Другие машины имели разные характеристики. Стандарт С наложил некоторые минимальные требования.

Стандарт C++ говорит это так:

3.9.1, §2:

Существует пять типов целых чисел со знаком: "char со знаком", "int", "int", "long int" и "long long int". В этом списке каждый тип обеспечивает как минимум столько же памяти, сколько предшествует ему в списке. Простые целые имеют естественный размер, предложенный архитектурой среды исполнения (44); другие подписанные целочисленные типы предоставляются для удовлетворения особых потребностей.

(44) то есть достаточно большим, чтобы содержать любое значение в диапазоне INT_MIN и INT_MAX, как определено в заголовке<climits>,

Вывод: это зависит от того, над какой архитектурой вы работаете. Любое другое предположение неверно.

Другие вопросы по тегам