Jaka jest różnica między int i long w C ++?

120

Popraw mnie, jeśli się mylę,

int to 4 bajty, z zakresem wartości od -2 147 483 648 do 2147 483647 (2 ^ 31)
long to 4 bajty, z zakresem wartości od -2 147 483 648 do 2 147 483 647 (2 ^ 31)

Jaka jest różnica w C ++? Czy można ich używać zamiennie?

Joel
źródło
W moim VS2005 działającym na 32-bitowym procesorze domyślny rozmiar int to 4 bajty.
Jeśli chcesz pisać kod przenośny, rozważ użycie, #include <stdint.h>a następnie typów, które określają rozmiar. Np uint32_t. Na nowej platformie musisz tylko upewnić się, że stdint.h działa prawidłowo dla tej konkretnej platformy, a kod działa zgodnie z przeznaczeniem.
BitTickler

Odpowiedzi:

112

Jest to zależne od implementacji.

Na przykład w systemie Windows są takie same, ale na przykład w systemach Alpha długość long wynosiła 64 bity, podczas gdy int - 32 bity. W tym artykule omówiono zasady dotyczące kompilatora Intel C ++ na platformach zmiennych. Podsumowują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  
Rob Walker
źródło
Myślę, że powinniśmy rozważyć połączenie tej odpowiedzi (odpowiedzi na przykładzie) z niektórymi szczegółami dotyczącymi standardu C ++ poniżej. Wersja robocza C ++ 0x znajduje się pod adresem open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf i jest oznaczona, aby można było zobaczyć różnice między nią a ostatnią wersją.
Patrick Johnmeyer,
Uwzględnienie czegoś we względnej kolejności według rozmiaru daje o wiele więcej informacji niż wyliczanie rozmiarów dla różnych platform - tak ładnie stwierdza @Kevin. (-1 głos)
xtofl
2
Niektóre kompilatory mają nawet flagi, które pozwalają na modyfikację domyślnego rozmiaru int i long, tj. Wymuszają na nich 8 lub 16 itd. Szczegóły znajdziesz w dokumentacji kompilatora.
Martin York,
7
Uwaga, to są rozmiary long
rogerdpack
1
Proszę podać również rozmiary int.
cegprakash
82

Jedyną gwarancją, jaką masz, są:

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

Zobacz także: Czy longgwarantowane jest co najmniej 32 bity?

Martin York
źródło
1
Hmm, to nie jest prawdą, jeśli sizeof (short)> = sizeof (char) znamy tylko ten sizeof (short)> = 1 (not> = 2), co przy okazji dotyczy wszystkich typów. Zgodnie z tym sizeof (dowolny typ całkowy)> = 1. Co jest prawdą, np. Pamiętam sizeof (int) == 1 na Z80, ale czy nie ma silniejszej gwarancji na długo?
Andreas Magnusson
6
3.9.1.2 standardu C ++ określa, że ​​sizeof (long)> = sizeof (int)> = sizeof (short)> = sizeof (char) 5.3.3.1 standardu C ++ określa, że ​​sizeof (char), sizeof (unsigned char) , a rozmiar (znak ze znakiem) jest równy 1. (cd ...)
KTC
4
(... cd) Maksymalne i minimalne wartości reprezentowane przez typy całkowite są zdefiniowane jako makra w <limits.h> (a zatem <climits>). Załącznik E do normy C (1990), który jest włączony przez odniesienie do standardu C ++, określa minimalne wielkości tych makr. (ciąg dalszy ...)
KTC,
4
(... cd.) i są to (2 ^ 15) -1, (2 ^ 15) -1, (2 ^ 31) -1, odpowiednio dla short, int i long, co okazuje się być wartością równą opublikowane przez Martina Yorka w jego odpowiedzi tutaj, jeśli CHAR_BIT wynosi 8 (co jest również jego minimalną wartością).
KTC,
2
@Giles: Czy to nie to, co powiedziałem powyżej? sizeof (short) * CHAR_BITS> = 16. Wybierz kilka innych rzeczy. :-)
Martin York
13

Podczas kompilacji dla x64 różnica między int i long wynosi od 0 do 4 bajtów, w zależności od używanego kompilatora.

GCC używa modelu LP64, co oznacza, że ​​wartości typu int są 32-bitowe, ale długie są 64-bitowe w trybie 64-bitowym.

Na przykład MSVC używa modelu LLP64, co oznacza, że ​​zarówno int, jak i long są 32-bitowe nawet w trybie 64-bitowym.

Adrian
źródło
prawdopodobnie 0 bajtów? hmm
rogerdpack
12

Sama specyfikacja C ++ (stara wersja, ale wystarczająco dobra do tego) pozostawia to otwarte.

Istnieją cztery typy liczb całkowitych ze znakiem: „ signed char”, „ short int”, „ int” i „ long int”. Na tej liście każdy typ zapewnia co najmniej tyle samo miejsca, co te poprzedzające go na liście. Zwykłe liczby int mają naturalny rozmiar sugerowany przez architekturę środowiska wykonawczego *;

[Przypis: to znaczy wystarczająco duży, aby zawierać dowolną wartość z zakresu INT_MIN i INT_MAX, zgodnie z definicją w nagłówku <climits>. --- end foonote]

Kevin Haines
źródło
7

Jak wskazuje Kevin Haines, ints mają naturalny rozmiar sugerowany przez środowisko wykonawcze, które musi mieścić się w INT_MIN i INT_MAX.

Standard C89 określa, że UINT_MAXpowinno to wynosić co najmniej 2 ^ 16-1, USHRT_MAX2 ^ 16-1 i ULONG_MAX2 ^ 32-1. To daje co najmniej 16 bitów dla short i int oraz 32 dla long. Dla char wyraźnie stwierdza, że ​​powinien mieć co najmniej 8 bitów ( CHAR_BIT). C ++ dziedziczy te reguły dla pliku limits.h, więc w C ++ mamy te same podstawowe wymagania dla tych wartości. Należy jednak nie wynikają z tego, że int jest co najmniej 2 bajt. Teoretycznie wszystkie znaki char, int i long mogą wynosić 1 bajt, w którym to przypadku CHAR_BITmusi wynosić co najmniej 32. Pamiętaj tylko, że „bajt” ma zawsze rozmiar znaku, więc jeśli znak jest większy, bajt to nie tylko 8 bitów więcej.

Johannes Schaub - litb
źródło
Nie sądziłem, że byteistnieje typ danych w C ++. Tak nie jest, prawda? Jeśli tak, a bytemoże mieć inne rozmiary niż 8 bitów, jest to po prostu głupie. Dlaczego mieliby nazywać to bajtem, jeśli absolutnie koniecznie jest to 8 bitów?
Alderath
6

To zależy od twojego kompilatora. Masz gwarancję, że long będzie co najmniej tak duży jak int, ale nie masz gwarancji, że będzie dłuższy.

Andru Luvisi
źródło
5

W większości przypadków liczba bajtów i zakres wartości jest określana przez architekturę procesora, a nie przez C ++. Jednak C ++ wyznacza minimalne wymagania, które litb poprawnie wyjaśnił, a Martin York popełnił tylko kilka błędów z.

Powodem, dla którego nie można używać zamiennie int i long, jest to, że nie zawsze mają taką samą długość. C został wynaleziony na PDP-11, gdzie bajt miał 8 bitów, int miał dwa bajty i mógł być obsługiwany bezpośrednio przez instrukcje sprzętowe. Ponieważ programiści C często potrzebowali czterobajtowej arytmetyki, wynaleziono long i było to cztery bajty, obsługiwane przez funkcje biblioteczne. Inne maszyny miały inne specyfikacje. Norma C nakładała pewne minimalne wymagania.

Programista Windows
źródło
5

Poleganie na implementacji prymitywnych rozmiarów typów przez dostawcę kompilatora POWRÓCI i prześladuje Cię, jeśli kiedykolwiek skompilujesz swój kod na innej architekturze maszyny, systemie operacyjnym lub kompilatorze innego dostawcy.

Większość dostawców kompilatorów udostępnia plik nagłówkowy, który definiuje typy pierwotne z jawnymi rozmiarami typów. Te typy pierwotne powinny być używane, gdy kod może zostać potencjalnie przeniesiony do innego kompilatora (czytaj to ZAWSZE w KAŻDEJ instancji). Na przykład większość kompilatorów UNIX ma int8_t uint8_t int16_t int32_t uint32_t. Microsoft ma INT8 UINT8 INT16 UINT16 INT32 UINT32. Wolę Borland / CodeGear int8 uint8 int16 uint16 int32 uint32. Nazwy te również przypominają nieco rozmiar / zakres zamierzonej wartości.

Od lat używam jawnych nazw typów pierwotnych Borlanda i #includenastępującego pliku nagłówkowego C / C ++ (primitive.h), który ma na celu zdefiniowanie jawnych typów pierwotnych z tymi nazwami dla dowolnego kompilatora C / C ++ (ten plik nagłówkowy może w rzeczywistości nie obejmować wszystkich kompilator, ale obejmuje kilka kompilatorów, których używałem na Windows, UNIX i Linux, również (jeszcze) nie definiuje typów 64-bitowych).

#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
Roger Nelson
źródło
C99 nakazuje, aby typdefy wyglądające jak int32_t, uint64_t itp. Były definiowane przez kompilator i miały dokładnie tyle bitów, ile sugeruje nazwa. Większość kompilatorów C ++ (w tym g ++) pozwoli ci użyć tych stałych w kodzie C ++.
rmeador
5

Standard C ++ mówi to tak:

3.9.1, §2:

Istnieje pięć typów liczb całkowitych ze znakiem: „signed char”, „short int”, „int”, „long int” i „long long int”. Na tej liście każdy typ zapewnia co najmniej tyle samo miejsca, co te poprzedzające go na liście. Zwykłe int mają naturalny rozmiar sugerowany przez architekturę środowiska wykonawczego (44); inne typy liczb całkowitych ze znakiem są dostarczane w celu spełnienia specjalnych potrzeb.

(44) to znaczy wystarczająco duże, aby zawierać dowolną wartość z zakresu INT_MIN i INT_MAX, zgodnie z definicją w nagłówku <climits> .

Wniosek: to zależy od architektury, nad którą pracujesz. Każde inne założenie jest fałszywe.

Jérôme Radix
źródło