Jaki jest rozmiar w bitach long w 64-bitowym systemie Windows?

137

Niedawno ktoś mi powiedział, że longna maszynach 64-bitowych nie ma 64 bitów i powinienem zawsze używać int. To nie miało dla mnie sensu. Widziałem dokumenty (takie jak ta na oficjalnej stronie Apple), które mówią, że longpodczas kompilacji dla 64-bitowego procesora mają rzeczywiście 64 bity. Sprawdziłem, co to jest w 64-bitowym systemie Windows i znalazłem

  • Windows: longi intpozostają 32-bitowe, a specjalne nowe typy danych są definiowane dla 64-bitowych liczb całkowitych.

(z http://www.intel.com/cd/ids/developer/asmo-na/eng/197664.htm?page=2 )

Czego powinienem użyć? Należy zdefiniować coś podobnego uw, sw((un) podpisali szerokość) jako longjeśli nie na Windows, a inaczej zrobić czek na bitsize cel procesora?

Csaba
źródło
W systemie Windows z MSVC ++ int i long są 32-bitowe: msdn.microsoft.com/en-us/library/3b2e7499.aspx . Jednak aby umożliwić np. Wektorom przechowywanie więcej niż 4G elementów, size_t jest 64-bitowa. Więc trzeba użyć int64_t zamiast int, aby iterować np. Wektory, które mogą zawierać więcej niż 4G elementów.
Serge Rogatch
@SergeRogatch powinni używać size_tlub typu iteratora do iteracji, nie intlubint64_t
phuclv
2
@ LưuVĩnhPhúc, size_tktóry staje się trudny w pobliżu liczb ujemnych, ponieważ size_tjest bez znaku. Więc for(size_t i=0; i<v.size()-2; i++)nie do wielkości wektora 0 i 1. Inny przykład: for(size_t i=v.size()-1; i>=0; i--).
Serge Rogatch
2
Jeśli robisz matematyki na wskaźnikach (czyli z size_twartości to wynik powinien być przechowywany w zmiennej ptrdiff_ttypu - który został zaprojektowany, aby być wystarczająco duże, aby utrzymać taki wynik i jest podpisany typ dla właśnie ten powód!)
SlySven

Odpowiedzi:

261

W świecie uniksowym istniało kilka możliwych konfiguracji rozmiarów liczb całkowitych i wskaźników dla platform 64-bitowych. Dwa najczęściej używane to ILP64 (właściwie tylko kilka przykładów; Cray był jednym z nich) i LP64 (do prawie wszystkiego innego). Akronynmy pochodzą od „int, long, wskaźniki są 64-bitowe” i „long, wskaźniki są 64-bitowe”.

Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64

Zrezygnowano z systemu ILP64 na rzecz LP64 (czyli prawie wszyscy późniejsi uczestnicy korzystali z LP64, w oparciu o zalecenia grupy Aspen; tylko systemy z długą tradycją 64-bitowego działania używają innego schematu). Wszystkie nowoczesne 64-bitowe systemy Unix używają LP64. MacOS X i Linux to nowoczesne systemy 64-bitowe.

Firma Microsoft używa innego schematu przejścia na wersję 64-bitową: LLP64 („długie długie, wskaźniki są 64-bitowe”). Ma to tę zaletę, że oznacza, że ​​oprogramowanie 32-bitowe można ponownie skompilować bez zmian. Ma wadę polegającą na tym, że różni się od tego, co robią wszyscy inni, a także wymaga korekty kodu, aby wykorzystać pojemność 64-bitową. Zawsze była konieczna korekta; był to po prostu inny zestaw poprawek niż te potrzebne na platformach Unix.

Jeśli projektujesz oprogramowanie w oparciu o nazwy typów całkowitych neutralnych dla platformy, prawdopodobnie przy użyciu <inttypes.h>nagłówka C99 , który, gdy typy są dostępne na platformie, zawiera podpisane (wymienione) i niepodpisane (niewymienione; przedrostek z literą „u”):

  • int8_t - 8-bitowe liczby całkowite
  • int16_t - 16-bitowe liczby całkowite
  • int32_t - 32-bitowe liczby całkowite
  • int64_t - 64-bitowe liczby całkowite
  • uintptr_t - liczby całkowite bez znaku wystarczająco duże, aby pomieścić wskaźniki
  • intmax_t- największy rozmiar liczby całkowitej na platformie (może być większy niż int64_t)

Następnie możesz zakodować swoją aplikację przy użyciu tych typów, jeśli ma to znaczenie, i bardzo ostrożnie z typami systemów (które mogą być różne). Istnieje intptr_ttyp - typ liczby całkowitej ze znakiem do przechowywania wskaźników; powinieneś planować nie używać go lub używać go tylko w wyniku odejmowania dwóch uintptr_twartości ( ptrdiff_t).

Ale, jak wskazuje pytanie (z niedowierzaniem), istnieją różne systemy rozmiarów całkowitych typów danych na maszynach 64-bitowych. Przyzwyczaić się do tego; świat się nie zmieni.

Jonathan Leffler
źródło
12
Dla tych, którzy są w pobliżu wystarczająco długo, przejście 64-bitowe ma pewne podobieństwa z przejściem 16-bitowym do 32-bitowym z połowy lat 80-tych. Były komputery, które były IL32 i inne, które były L32 (dostosowujące nową notację do starego problemu). Czasami „int” było 16-bitowe, czasami 32-bitowe.
Jonathan Leffler
4
Nie zapominaj, że dotyczy to tylko języków C-ish. Inne mają rozsądniejsze specyfikacje, w których a) program piszący kompilator nie może wybierać rozmiaru typów danych w sposób dowolny lub b) fizyczna reprezentacja typów danych nie „przecieka” lub c) liczby całkowite są zawsze nieskończenie duże.
Jörg W Mittag,
2
To prawda - ale w przypadku języków, które określają zachowanie, po pierwsze nie ma problemu. Na przykład Java ma „długi”, ale rozmiar jest stały (64-bitowy?) Na wszystkich platformach. Nie ma więc problemów z przenoszeniem do maszyny 64-bitowej; rozmiar się nie zmienia.
Jonathan Leffler,
17
@TomFobear: ILP64 przedstawia jeden główny problem - jak nazywasz typ 32-bitowy? Lub, jeśli nazwiesz typ 32-bitowy short, jak nazwiesz typ 16-bitowy? A jeśli nazwiesz typ 16-bitowy chardla UTF-16 itp., Jak nazwiesz typ 8-bitowy? Tak więc, użycie LP64 daje ci 8-bitowy char, 16-bitowy short, 32-bitowy int, 64-bitowy long, z miejscem na rozszerzenie do 128-bitowego, long longkiedy (jeśli?) Stanie się to istotne. Potem masz więcej potęg 256 niż nazwy w C (cóż, przypuszczam, że możesz mieć 256-bitowe intmax_ti dopiero wtedy się wyczerpią). LP64 ma swoje zalety.
Jonathan Leffler
2
Może jest to dla was oczywiste, ale myślę, że warto zauważyć, że C # używa innych rozmiarów liczb całkowitych niż wszystko inne. Niedawno wpadłem na interakcję z biblioteką DLL, ponieważ C # używa 64-bitowych długości ( msdn.microsoft.com/en-us/library/ms173105.aspx ).
Compholio
57

Nie jest jasne, czy pytanie dotyczy kompilatora Microsoft C ++, czy interfejsu API systemu Windows. Jednak nie ma tagu [c ++], więc zakładam, że dotyczy interfejsu API systemu Windows. Niektóre odpowiedzi cierpią z powodu gnicia linków, więc podaję kolejny link, który może się zgnić.


Aby uzyskać więcej informacji na temat typów, takich jak Windows API INT, LONGitd. Istnieje strona na MSDN:

Typy danych systemu Windows

Informacje są również dostępne w różnych plikach nagłówkowych Windows, takich jak WinDef.h. Wymieniłem tutaj kilka odpowiednich typów:

Wpisz | S / U | x86 | x64
---------------------------- + ----- + -------- + ------ -
BYTE, BOOLEAN | U | 8 bitów | 8 bitowy
---------------------------- + ----- + -------- + ------ -
KRÓTKI | S | 16-bitowy | 16 bitów
USHORT, SŁOWO | U | 16-bitowy | 16 bitów
---------------------------- + ----- + -------- + ------ -
INT, LONG | S | 32-bitowy | 32-bitowy
UINT, ULONG, DWORD | U | 32-bitowy | 32-bitowy
---------------------------- + ----- + -------- + ------ -
INT_PTR, LONG_PTR, LPARAM | S | 32-bitowy | 64-bitowy
UINT_PTR, ULONG_PTR, WPARAM | U | 32-bitowy | 64-bitowy
---------------------------- + ----- + -------- + ------ -
DŁUGIE | S | 64-bitowy | 64-bitowy
ULONGLONG, QWORD | U | 64-bitowy | 64-bitowy

Kolumna „S / U” oznacza ze znakiem / bez znaku.

Martin Liversage
źródło
4

Ten artykuł na temat MSDN odwołuje się do szeregu aliasów typów (dostępnych w systemie Windows), które są nieco bardziej wyraźne pod względem ich szerokości:

http://msdn.microsoft.com/en-us/library/aa505945.aspx

Na przykład, chociaż możesz użyć ULONGLONG do odniesienia do 64-bitowej wartości całkowitej bez znaku, możesz również użyć UINT64. (To samo dotyczy ULONG i UINT32.) Być może te będą nieco jaśniejsze?

reuben
źródło
1
Czy jest jakaś gwarancja, że ​​uint32_t i DWORD będą wymienne? Nietrudno sobie wyobrazić, że mogą nie być [np. Jeśli pierwszy jest 32-bitowy, inta drugi 32-bitowy long, gcc założyłby, że wskaźnik do jednego typu nie byłby w stanie aliasować drugiego pomimo ich pasujących reprezentacji].
supercat
4

Firma Microsoft zdefiniowała również UINT_PTR i INT_PTR dla liczb całkowitych, które mają taki sam rozmiar jak wskaźnik.

Oto lista specyficznych typów firmy Microsoft - jest to część odniesienia do sterowników, ale uważam, że jest to również ważne dla ogólnego programowania.

Mark Okup
źródło
2

Najłatwiejszy sposób na poznanie tego dla twojego kompilatora / platformy:

#include <iostream>

int main() {
  std::cout << sizeof(long)*8 << std::endl;
}

Mnożenie przez 8 ma na celu uzyskanie bitów z bajtów.

Gdy potrzebujesz określonego rozmiaru, często najłatwiej jest użyć jednego z predefiniowanych typów biblioteki. Jeśli jest to niepożądane, możesz zrobić to, co często dzieje się z oprogramowaniem autoconf i poprosić system konfiguracji o określenie odpowiedniego typu dla wymaganego rozmiaru.

Paul de Vrieze
źródło
4
Nie żeby to miało znaczenie, ale 8-bitowe bajty nie są w rzeczywistości częścią specyfikacji C (klauzula 3.6 i 5.2.4.2.1 standardu C). Chociaż trudno byłoby znaleźć maszynę, w której nie ma 8 bitów, możesz sprawdzić LONG_BIT, aby zobaczyć, jak duży jest twój długi typ danych.
Andres
Oczywiście masz rację, w rzeczywistości jest to zależne od architektury („adresowalna jednostka przechowywania danych wystarczająco duża, aby pomieścić dowolnego członka podstawowego zestawu znaków środowiska wykonawczego”), ale najczęściej używane architektury są równe 8 bitom.
Paul de Vrieze,
Ale OP nie pytał o swój kompilator / platformę; zapytał konkretnie o 64-bitowy system Windows - prawdopodobnie dlatego, że nie ma wygodnego dostępu do 64-bitowego systemu Windows do testowania.
Quuxplusone
0

Rozmiar w bitach longna platformach Windows wynosi 32 bity (4 bajty).

Możesz to sprawdzić za pomocą sizeof(long).

BeeOnRope
źródło
-2

Jeśli potrzebujesz użyć liczb całkowitych o określonej długości, prawdopodobnie powinieneś użyć nagłówków niezależnych od platformy. Boost to dobre miejsce do obejrzenia.

PolyThinker
źródło