Jaki standard C ++ określa rozmiar int, długi typ?

696

Szukam szczegółowych informacji dotyczących wielkości podstawowych typów C ++. Wiem, że zależy to od architektury (16 bitów, 32 bity, 64 bity) i kompilatora.

Ale czy są jakieś standardy dla C ++?

Korzystam z programu Visual Studio 2008 w architekturze 32-bitowej. Oto co otrzymuję:

char  : 1 byte
short : 2 bytes
int   : 4 bytes
long  : 4 bytes
float : 4 bytes
double: 8 bytes

Starałem się znaleźć bez większych sukcesów, wiarygodne informacje określające rozmiary char, short, int, long, double, float(i inne rodzaje I nie myśleć) w różnych architektur i kompilatory.

Jérôme
źródło
18
@ nie zmieniaj go z wyboru ... istnieje tak wiele architektur do obsługi, że musi być elastyczny.
Krakkos
4
Dlaczego nie usuwają wszystkich niejasnych typów i nie standaryzują ich do określonych typów długości bitów, np. Int32_t, uint32_t, int64_t itp.
developerbmw
5
@thyrgle W rzeczywistości dość trudno jest ustandaryzować coś takiego. W przeciwieństwie do Javy, gdzie rzeczy te są stałe ze względu na sposób działania JVM, C / C ++ zasadniczo musi trzymać się systemu, na którym jest uruchamiany, bez żadnych warstw abstrakcji fantazyjnie-pancy (przynajmniej nie tak wiele jak w Javie) pomiędzy. Jeżeli wielkość int jest ważne można użyć int16_t, int32_ti int64_t(potrzebne iostreamto za to jeśli dobrze pamiętam). Co jest miłego w tym, że int64_t nie powinien mieć problemów w systemie 32-bitowym (wpłynie to jednak na wydajność).
rbaleksandar
5
@rbaleksandar Są w rzeczywistości zdefiniowani <cstdint>, a nie <iostream>.
Justin Time - Przywróć Monikę

Odpowiedzi:

685

Standard C ++ nie określa wielkości typów całek w bajtach, ale określa minimalne zakresy, które muszą być w stanie pomieścić. Możesz określić minimalny rozmiar w bitach z wymaganego zakresu. Na podstawie tego można wywnioskować minimalny rozmiar w bajtach oraz wartość CHAR_BITmakra, która określa liczbę bitów w bajcie . Na wszystkich mało znanych platformach jest to 8 i nie może być mniejsza niż 8. To dlatego, że musi być wystarczająco duża, aby pomieścić „ośmiobitowe jednostki kodu w formie kodowania Unicode UTF-8”.

Jednym dodatkowym ograniczeniem charjest to, że jego rozmiar wynosi zawsze 1 bajt lub CHAR_BITbit (stąd nazwa). Jest to wyraźnie określone w normie.

Standard C jest odniesieniem normatywnym do standardu C ++, więc nawet jeśli nie określa on wyraźnie tych wymagań, C ++ wymaga minimalnych zakresów wymaganych przez standard C (strona 22), które są takie same jak w zakresach typów danych na MSDN :

  1. signed char: Od -127 do 127 (uwaga, nie od -128 do 127; dotyczy to komplementów 1 i platform znak-i-wielkości)
  2. unsigned char: Od 0 do 255
  3. „zwykły” char: ten sam zakres co signed charlub unsigned char, zdefiniowany w implementacji
  4. signed short: Od -32767 do 32767
  5. unsigned short: Od 0 do 65535
  6. signed int: Od -32767 do 32767
  7. unsigned int: Od 0 do 65535
  8. signed long: -2147483647 do 2147483647
  9. unsigned long: Od 0 do 4294967295
  10. signed long long: -9223372036854775807 do 9223372036854775807
  11. unsigned long long: Od 0 do 18446744073709551615

Implementacja C ++ (lub C) może definiować rozmiar typu w bajtach sizeof(type)do dowolnej wartości, o ile

  1. wyrażenie sizeof(type) * CHAR_BITocenia na liczbę bitów wystarczająco wysoką, aby zawierać wymagane zakresy, oraz
  2. kolejność typów jest nadal ważna (np sizeof(int) <= sizeof(long).).

Podsumowując, gwarantujemy, że:

  • char, signed chari unsigned charmają co najmniej 8 bitów
  • signed short, unsigned short, signed int, A unsigned intco najmniej 16 bitów
  • signed longi unsigned longmają co najmniej 32 bity
  • signed long longi unsigned long longmają co najmniej 64 bity

Nie udziela się gwarancji co do wielkości floatlub doublez wyjątkiem, że doublezapewnia ona co najmniej tyle precyzji, co float.

Rzeczywiste zakresy specyficzne dla implementacji można znaleźć w <limits.h>nagłówku w C lub <climits>w C ++ (lub nawet lepiej, w szablonie std::numeric_limitsw <limits>nagłówku).

Na przykład w ten sposób znajdziesz maksymalny zasięg dla int:

DO:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++ :

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();
Alex B.
źródło
49
Zamiast tego w standardzie C ++ słowo bajt oznacza „1 char”, a nie zwykłe znaczenie.
Ben Voigt
4
@ Programmer Przeczytaj odpowiedź (uwaga w punkcie 1 w nawiasach) lub treść standardu (połączona w odpowiedzi). Standard C obsługuje architektury uzupełnienia 1, które mają inną reprezentację niż najbardziej rozpowszechnione uzupełnienie 2. Minimalne gwarantowane zakresy prawie zawsze będą różnić się od faktycznych zakresów zapewnianych przez implementację.
Alex B
9
@Alex B, w swojej odpowiedzi nie wspominałeś nic o double. Czy możesz zaktualizować swoją odpowiedź dla zmiennych zmiennoprzecinkowych?
Cool_Coder
3
@Cool_Coder: zmiennoprzecinkowy to cały dodatkowy czajnik z rybami, łatwo podwajający rozmiar słupków.
Deduplicator
3
@Mooing Duck: „wszystkie wersje C ++ wymagały 256 różnych wartości [dla podpisanych typów znaków]” Nie, to nie było prawdą, dopóki nie zostało to naprawione w nowszych specyfikacjach C ++. Starsze specyfikacje zezwalały podpisanym typom znaków na wzorce bitów, które nie są odwzorowywane na liczby, więc brakowało wymogu 256 różnych wartości. „W przypadku niepodpisanych typów znaków wszystkie możliwe wzorce bitowe reprezentacji wartości reprezentują liczby. Te wymagania nie dotyczą innych typów.”
Adrian McCarthy
241

W przypadku systemów 32-bitowych standardem de facto jest ILP32 - to znaczy int, longa wskaźnik to 32-bitowe wielkości.

W systemach 64-bitowych podstawowym uniksowym standardem „de facto” jest LP64 - longa wskaźnik jest 64-bitowy (ale int32-bitowy). Standardowe 64-bitowy Windows jest LLP64 - long longi wskaźnik są 64-bitowe (ale longi intto zarówno 32-bit).

Kiedyś niektóre systemy uniksowe korzystały z organizacji ILP64.

Żadna z tych de facto norm nie jest uregulowana normą C (ISO / IEC 9899: 1999), ale wszystkie są przez nią dozwolone.

I z definicji sizeof(char)jest to 1pomimo testu w skrypcie konfiguracyjnym Perla.

Zauważ, że nie było maszyny (Crays), gdzie CHAR_BITbył znacznie większy niż 8. To oznaczało, IIRC, że sizeof(int)był również 1, ponieważ zarówno chari intbyły 32-bitowe.

Jonathan Leffler
źródło
73
+1 za stwierdzenie, jakie rzeczy są naprawdę w sprawach, które są najważniejsze, a nie jak teoria jest w teorii. Jeśli chcesz mieć 32-bitowy int, jeśli chcesz 64-bitowy, użyj długiego. Jeśli chcesz natywny, użyj size_t. Unikaj „zwykłego” długiego, ponieważ jest różny. To powinno działać w przypadku większości aplikacji.
Eloff
37
+1 za odpowiedź. @Eloff: wręcz przeciwnie ... jeśli chcesz użyć wersji 32-bitowej [u]int32_tlub podobnej, jeśli chcesz użyć wersji 64-bitowej [u]int64_t... jeśli nie masz dla nich nagłówka, pobierz go lub zrób, najlepiej z wyborem czasu kompilacji takie typy lub twierdzenia statyczne w celu weryfikacji rozmiaru. pubs.opengroup.org/onlinepubs/009695299/basedefs/stdint.h.html Jeśli dokładne rozmiary nie są tak ważne i zależy Ci tylko na ich wielkości, to twoja rada dotyczy popularnych współczesnych platform PC / serwerów.
Tony Delroy,
8
Zauważ, że nie tylko stare maszyny do raków mają CHAR_BIT> 8. np. DSP często mają CHAR_BIT 16 lub 32. (patrz np. Te )
nos
2
@nos: Dziękujemy za link. Bardzo pomocne jest zidentyfikowanie nowoczesnych, aktualnych systemów dla przypadków nieparzystych. Z ciekawości, jaki kod jest ustawiony na tych komputerach? Jeśli zestawem kodów jest UTF-16, to 0xFFFF nie jest prawidłowym znakiem, a jeśli zestawem kodów jest zestaw kodów ISO 8859-x, to znowu 0xFFFF nie jest prawidłowym znakiem (kody znaków od 0x00 do 0xFF są poprawne). Nie jestem jeszcze przekonany, że istnieje problem z wykryciem EOF, ale z pewnością jest miejsce na ostrożność, i prawdopodobnie na pisanie i używanie funkcji, int get_char(FILE *fp, char *c)która zwraca EOF lub 0 i ustawia *c.
Jonathan Leffler
2
@joelw: C11 wymaga, biorąc uint32_t x=1,y=2;pod uwagę, że wartość x-ymusi wynosić 4294967295 na platformach, na których „int” wynosi 32 bity lub mniej, oraz -1 na platformach, na których „int” ma 33 bity lub więcej. Ponadto wymaga x*yoceny, która musi być oszacowana przy użyciu arytmetyki modułowej dla wszystkich wartości xiy, jeżeli „int” wynosi 32 bity lub mniej, oraz konwencjonalnej arytmetyki, jeśli 65 bitów lub więcej, ale nie nakłada żadnych wymagań na to, co może się stać z dużymi wartościami z xiy, jeżeli „int” ma od 33 do 64 bitów.
supercat
88

W praktyce nie ma czegoś takiego. Często można oczekiwać, std::size_tże w obecnej architekturze będzie reprezentował rozmiar całkowitą bez znaku dla rodzimej liczby całkowitej. tj. 16-bitowy, 32-bitowy lub 64-bitowy, ale nie zawsze tak jest, jak wskazano w komentarzach do tej odpowiedzi.

Jeśli chodzi o wszystkie inne typy wbudowane, tak naprawdę zależy to od kompilatora. Oto dwa fragmenty zaczerpnięte z aktualnej wersji roboczej najnowszego standardu C ++:

Istnieje pięć standardowych typów liczb całkowitych ze znakiem: znak, char, short int, int, long int i long long int. Na tej liście każdy typ zapewnia co najmniej tyle miejsca, ile poprzedza go na liście.

Dla każdego ze standardowych standardowych liczb całkowitych ze znakiem istnieje odpowiedni (ale inny) standardowy typ liczb całkowitych bez znaku: unsigned char, unsigned short int, unsigned int int, unsigned long int i unsigned long long int, z których każdy zajmuje taką samą ilość przechowywania i ma takie same wymagania dotyczące wyrównania.

Jeśli chcesz, możesz statycznie (czas kompilacji) potwierdzić rozmiar tych podstawowych typów. Ostrzeże ludzi, aby pomyśleli o przeniesieniu kodu, jeśli zmieni się rozmiar założeń.

John Leidegren
źródło
7
dobry post. Kolejną rzeczą, która jest wymagana, są następujące najmniejsze rozmiary bitów (udokumentowane w c89 / c99 wraz z limitami.h i przejęte przez c ++): char> = 8, short i int> = 16, long> = 32.
Johannes Schaub - litb
1
Również na 8-bitowej platformie AVR size_t nie będzie 8 bitów, ale 16, ponieważ rozmiary wskaźnika i int są 16 bitów. Więc rozmiar danych natywnych procesora nie jest związany z size_t.
Robotbugs
80

Jest standard.

Wymaga tego standard C90

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

Wymaga tego standard C99

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

Oto specyfikacja C99 . Strona 22 zawiera informacje o rozmiarach różnych typów całek.

Oto rozmiary typu int (bity) dla platform Windows:

Type           C99 Minimum     Windows 32bit
char           8               8
short          16              16
int            16              32
long           32              32
long long      64              64

Jeśli martwisz się przenośnością lub chcesz, aby nazwa typu odzwierciedlała rozmiar, możesz spojrzeć na nagłówek <inttypes.h>, w którym dostępne są następujące makra:

int8_t
int16_t
int32_t
int64_t

int8_tma gwarantowane 8 bitów i int16_t16 bitów itp.

yinyueyouge
źródło
8
Drobny nitpick: gdzie mówi standard, sizeof(long) < sizeof(long long)a nie symetryczny sizeof(long) <= sizeof(long long)?
Jonathan Leffler
2
@JonathonLeffler - patrz C99 5.2.4.2.1 - Rozmiary typów całkowitych. minsizeof (int) == 16-bitów, minsizeof (long) == 32-bitów, minsizeof (long long) == 64-bitów. Więc myślę, że masz rację <=, ponieważ nie określono żadnego parametru maxsizeof (typ).
Jesse Chisholm
Podobnie sizeof (float) <= sizeof (double) <= sizeof (long double). Zgodnie z C99 7.12 ust. 2
Jesse Chisholm
38

Jeśli potrzebujesz typów o ustalonym rozmiarze, użyj typów takich jak uint32_t (liczba całkowita 32 bez znaku) zdefiniowanych w stdint.h . Są one określone w C99 .

Ben
źródło
10
Są określone, ale nie wymagane.
dreamlax
2
@dreamlax Jakie platformy go nie obejmują?
Levi Morrison
3
@LeviMorrison: Każda platforma, która nie ma ich w wymaganej formie. Platforma, która CHAR_BIT == 16na przykład nie będzie miała int8_t. Każda platforma nieużywająca uzupełnienia dwóch nie będzie miała żadnego z nich (ponieważ standard wymaga uzupełnienia dwóch).
DevSolar,
36

Zaktualizowano: C ++ 11 oficjalnie wprowadził typy z TR1 do standardu:

  • long long int
  • unsigned long long int

I typy „wielkości” z <cstdint>

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • (i niepodpisane odpowiedniki).

Plus dostajesz:

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • Plus niepodpisane odpowiedniki.

Te typy reprezentują najmniejsze typy liczb całkowitych z co najmniej określoną liczbą bitów. Podobnie istnieją „najszybsze” typy liczb całkowitych z co najmniej określoną liczbą bitów:

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • Plus niepodpisane wersje.

To, co „szybko” znaczy, zależy od wdrożenia. Nie musi być najszybszy do wszystkich celów.

Brian Neal
źródło
Jest to teraz część standardu C ++ 11.
Jaan
2
„szybki” oznacza po prostu dostosowany do architektury sprzętowej. Jeśli rejestry są 16-bitowe, to int_fast8_t jest wartością 16-bitową. Jeśli rejestry są 32-bitowe, to zarówno int_fast8_t, jak i int_fast16_t są wartościami 32-bitowymi. itd. Patrz C99 sekcja 7.18.1.3 akapit 2.
Jesse Chisholm
19

Standard C ++ mówi tak:

3.9.1, ust. 2:

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

(44), czyli wystarczająco duży, aby zawierać dowolną wartość z zakresu INT_MIN i INT_MAX, jak zdefiniowano w nagłówku <climits> .

Wniosek: zależy od architektury, nad którą pracujesz. Wszelkie inne założenia są fałszywe.

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

Nie, nie ma standardu dla rozmiarów typów. Standard wymaga jedynie, aby:

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

Najlepszą rzeczą, jaką możesz zrobić, jeśli chcesz mieć zmienne o stałych rozmiarach, jest użycie takich makr:

#ifdef SYSTEM_X
  #define WORD int
#else
  #define WORD long int
#endif

Następnie możesz użyć WORD do zdefiniowania zmiennych. To nie tak, że to lubię, ale jest to najbardziej przenośny sposób.

Emiliano
źródło
4
Problem polega na tym, że WORD rozprzestrzenia się po programie na obszary, które nie są tak naprawdę zależne od ustalonego rozmiaru (spójrz na niektóre kody systemu Windows). Jak się dowiedziałem, przechodząc z systemu 16-bitowego na 32-bitowy, masz ten sam problem, który miał rozwiązać WORD.
lilburne
@liburne Oczywiście powinieneś używać WORD tylko wtedy, gdy potrzebujesz zmiennej wielkości o stałym rozmiarze, na przykład podczas czytania / pisania z / do pliku. Jeśli fragment kodu nie jest tak naprawdę zależny od ustalonego rozmiaru, powinieneś użyć normalnych zmiennych „int”.
Emiliano
3
Najlepszą rzeczą, jaką możesz zrobić, aby uzyskać przenośne rozmiary, powinien być#include <boost/cstdint.hpp>
kizzx2
11

Możemy zdefiniować synonim tego typu, abyśmy mogli stworzyć własny „standard”.

Na maszynie, w której sizeof (int) == 4, możemy zdefiniować:

typedef int int32;

int32 i;
int32 j;
...

Kiedy więc przeniesiemy kod na inną maszynę, gdzie faktycznie długość długiej int wynosi 4, możemy po prostu przedefiniować pojedyncze wystąpienie int.

typedef long int int32;

int32 i;
int32 j;
...
milan-j
źródło
1
Nie jest to konieczne, biorąc pod uwagę standardowy nagłówek <stdint.h>(C99 i późniejsze, i którykolwiek standard C ++ przyjął wersję C99 biblioteki C).
Keith Thompson
8

W przypadku liczb zmiennoprzecinkowych istnieje standard (IEEE754) : liczby zmiennoprzecinkowe są 32-bitowe, a liczby podwójne to 64. Jest to standard sprzętowy, a nie standard C ++, więc kompilatory mogą teoretycznie definiować zmiennoprzecinkowe i podwójne do innych rozmiarów, ale w praktyce I ' nigdy nie widziałem architektury, która używałaby czegoś innego.

Crashworks
źródło
2
Jednak zgodność z IEEE 754 (alias IEC 559) jest opcjonalna w C ++ (prawdopodobnie również C, ale nie jestem pewien). Zobacz std :: numeric_limits :: is_iec559.
Drew Hall
1
Wtedy nie widziałeś kompilatora TI dla DSP TMS320C28xx, gdzie doublema taki sam rozmiar jak float(i inttaki sam, jak charoba są 16-bitowe). Ale mają 64-bit long double.
starblue
7

Istnieje norma, która jest określona w różnych dokumentach dotyczących norm (ISO, ANSI i tak dalej).

Wikipedia ma świetną stronę wyjaśniającą różne typy i maksymalną liczbę, jaką mogą przechowywać: Integer w dziedzinie informatyki.

Jednak nawet przy standardowym kompilatorze C ++ można stosunkowo łatwo dowiedzieć się, używając następującego fragmentu kodu:

#include <iostream>
#include <limits>


int main() {
    // Change the template parameter to the various different types.
    std::cout << std::numeric_limits<int>::max() << std::endl;
}

Dokumentację dla std :: numeric_limits można znaleźć na Roguewave . Zawiera mnóstwo innych poleceń, które można wywołać, aby poznać różne ograniczenia. Można tego używać z dowolnym dowolnym typem, który przekazuje rozmiar, na przykład std :: streamsize.

Odpowiedź Jana zawiera najlepszy opis, ponieważ są one gwarantowane. Bez względu na to, na jakiej platformie się znajdujesz, istnieje jeszcze jedna dobra strona, która zawiera bardziej szczegółowe informacje na temat liczby bitów każdego typu MUSI zawierać: typy int , które są zdefiniowane w standardzie.

Mam nadzieję, że to pomoże!

X-Istence
źródło
7

Możesz użyć:

cout << "size of datatype = " << sizeof(datatype) << endl;

datatype = int, long intitp. Będziesz mógł zobaczyć rozmiar dla dowolnego typu danych, który wpiszesz.

Population Xplosive
źródło
7

Jeśli chodzi o typy wbudowane dla różnych architektur i różnych kompilatorów, po prostu uruchom następujący kod na swojej architekturze z kompilatorem, aby zobaczyć, co wyprowadza. Poniżej pokazano moje wyjście Ubuntu 13.04 (Raring Ringtail) 64-bitowe g ++ 4.7.3. Zwróć również uwagę na poniższe odpowiedzi, dlatego dane wyjściowe są zamawiane jako takie:

„Istnieje pięć standardowych typów liczb całkowitych ze znakiem: podpisany char, short int, int, long int i long long int. Na tej liście każdy typ zapewnia co najmniej tyle samo miejsca, co poprzedzające go na liście”.

#include <iostream>

int main ( int argc, char * argv[] )
{
  std::cout<< "size of char: " << sizeof (char) << std::endl;
  std::cout<< "size of short: " << sizeof (short) << std::endl;
  std::cout<< "size of int: " << sizeof (int) << std::endl;
  std::cout<< "size of long: " << sizeof (long) << std::endl;
  std::cout<< "size of long long: " << sizeof (long long) << std::endl;

  std::cout<< "size of float: " << sizeof (float) << std::endl;
  std::cout<< "size of double: " << sizeof (double) << std::endl;

  std::cout<< "size of pointer: " << sizeof (int *) << std::endl;
}


size of char: 1
size of short: 2
size of int: 4
size of long: 8
size of long long: 8
size of float: 4
size of double: 8
size of pointer: 8
bjackfly
źródło
sizeof(char)nie powinien być uwzględniony.
Ven
3

Jak wspomniano, rozmiar powinien odzwierciedlać obecną architekturę. Możesz limits.hsprawdzić, czy twój obecny kompilator radzi sobie z różnymi rzeczami.

John T.
źródło
Dzięki, ale chciałbym poznać rozmiary Achitectures, których sam nie mam (jak 64 bity). Ten samouczek mówi tylko o achitekturach 32-bitowych ...
Jérôme
2

Jak odpowiedzieli inni, wszystkie „standardy” pozostawiają większość szczegółów jako „implementację zdefiniowaną” i tylko stwierdzają, że typ „char” jest co najmniej „char_bis” szeroki, a „char <= krótki <= int <= długi < = long long ”(liczba zmiennoprzecinkowa i liczba podwójna są prawie zgodne ze standardami zmiennoprzecinkowymi IEEE, a długość podwójna jest zwykle taka sama jak liczba podwójna - ale może być większa w przypadku bardziej aktualnych implementacji).

Jednym z powodów braku konkretnych i dokładnych wartości jest to, że języki takie jak C / C ++ zostały zaprojektowane tak, aby były przenośne na wiele platform sprzętowych - w tym systemy komputerowe, w których rozmiar słowa „char” może wynosić 4 bity lub 7-bitów, a nawet niektórych wartości innych niż komputery „8- / 16- / 32- / 64-bit”, na które narażony jest przeciętny użytkownik komputera domowego. (Rozmiar słowa w tym przypadku oznacza, ile bitów w całym systemie normalnie działa - Ponownie, nie zawsze jest to 8 bitów, jak mogą się spodziewać użytkownicy komputerów domowych).

Jeśli naprawdę potrzebujesz obiektu (w sensie serii bitów reprezentujących wartość całkowitą) o określonej liczbie bitów, większość kompilatorów ma jakąś metodę określenia tego; Ale na ogół nie jest przenośny, nawet między kompilatorami firmy ame, ale na różne platformy. Niektóre standardy i praktyki (szczególnie ograniczenia. Hi podobne) są na tyle powszechne, że większość kompilatorów będzie obsługiwać określanie typu najlepiej dopasowanego do określonego zakresu wartości, ale nie liczby używanych bitów. (To znaczy, jeśli wiesz, że musisz przechowywać wartości od 0 do 127, możesz ustalić, że twój kompilator obsługuje 8-bitowy typ „int8”, który będzie wystarczająco duży, aby pomieścić żądany pełny zakres, ale nie coś w rodzaju typ „int7”, który byłby dokładnym dopasowaniem dla 7 bitów.)

Uwaga: Wiele pakietów źródłowych Un * x używało skryptu „./configure”, który sprawdza możliwości kompilatora / systemu i wyświetla odpowiedni plik Makefile i config.h. Możesz zbadać niektóre z tych skryptów, aby zobaczyć, jak one działają i jak sprawdzają możliwości systemu kompilatora / systemu i podążają za nimi.

CM
źródło
1

Jeśli jesteś zainteresowany czystym rozwiązaniem C ++, skorzystałem z szablonów i tylko standardowego kodu C ++ do definiowania typów w czasie kompilacji na podstawie ich wielkości bitów. Dzięki temu rozwiązanie jest przenośne dla różnych kompilatorów.

Pomysł jest bardzo prosty: utwórz listę zawierającą typy char, int, short, long, long long (wersje podpisane i niepodpisane), a następnie zeskanuj listę i za pomocą szablonu numeric_limits wybierz typ o danym rozmiarze.

Łącznie z tym nagłówkiem masz 8 typów stdtype :: int8, stdtype :: int16, stdtype :: int32, stdtype :: int64, stdtype :: uint8, stdtype :: uint16, stdtype :: uint32, stdtype :: uint64.

Jeśli jakiś typ nie może być reprezentowany, zostanie przetworzony na stdtype :: null_type również zadeklarowany w tym nagłówku.

PONIŻSZY KOD JEST UDANY BEZ GWARANCJI, PROSIMY O PODWÓJNE SPRAWDZENIE.
JESTEM NOWY W METAPROGRAMMINGU, ZAPRASZAMY DO EDYCJI I PRAWIDŁOWEGO TEGO KODU.
Testowane z DevC ++ (więc wersja gcc około 3.5)

#include <limits>

namespace stdtype
{
    using namespace std;


    /*
     * THIS IS THE CLASS USED TO SEMANTICALLY SPECIFY A NULL TYPE.
     * YOU CAN USE WHATEVER YOU WANT AND EVEN DRIVE A COMPILE ERROR IF IT IS 
     * DECLARED/USED.
     *
     * PLEASE NOTE that C++ std define sizeof of an empty class to be 1.
     */
    class null_type{};

    /*
     *  Template for creating lists of types
     *
     *  T is type to hold
     *  S is the next type_list<T,S> type
     *
     *  Example:
     *   Creating a list with type int and char: 
     *      typedef type_list<int, type_list<char> > test;
     *      test::value         //int
     *      test::next::value   //char
     */
    template <typename T, typename S> struct type_list
    {
        typedef T value;
        typedef S next;         

    };




    /*
     * Declaration of template struct for selecting a type from the list
     */
    template <typename list, int b, int ctl> struct select_type;


    /*
     * Find a type with specified "b" bit in list "list"
     *
     * 
     */
    template <typename list, int b> struct find_type
    {   
        private:
            //Handy name for the type at the head of the list
            typedef typename list::value cur_type;

            //Number of bits of the type at the head
            //CHANGE THIS (compile time) exp TO USE ANOTHER TYPE LEN COMPUTING
            enum {cur_type_bits = numeric_limits<cur_type>::digits};

        public:
            //Select the type at the head if b == cur_type_bits else
            //select_type call find_type with list::next
            typedef  typename select_type<list, b, cur_type_bits>::type type;
    };

    /*
     * This is the specialization for empty list, return the null_type
     * OVVERRIDE this struct to ADD CUSTOM BEHAVIOR for the TYPE NOT FOUND case
     * (ie search for type with 17 bits on common archs)
     */
    template <int b> struct find_type<null_type, b>
    {   
        typedef null_type type;

    };


    /*
     * Primary template for selecting the type at the head of the list if
     * it matches the requested bits (b == ctl)
     *
     * If b == ctl the partial specified templated is evaluated so here we have
     * b != ctl. We call find_type on the next element of the list
     */
    template <typename list, int b, int ctl> struct select_type
    {   
            typedef  typename find_type<typename list::next, b>::type type; 
    };

    /*
     * This partial specified templated is used to select top type of a list
     * it is called by find_type with the list of value (consumed at each call)
     * the bits requested (b) and the current type (top type) length in bits
     *
     * We specialice the b == ctl case
     */
    template <typename list, int b> struct select_type<list, b, b>
    {
            typedef typename list::value type;
    };


    /*
     * These are the types list, to avoid possible ambiguity (some weird archs)
     * we kept signed and unsigned separated
     */

    #define UNSIGNED_TYPES type_list<unsigned char,         \
        type_list<unsigned short,                           \
        type_list<unsigned int,                             \
        type_list<unsigned long,                            \
        type_list<unsigned long long, null_type> > > > >

    #define SIGNED_TYPES type_list<signed char,         \
        type_list<signed short,                         \
        type_list<signed int,                           \
        type_list<signed long,                          \
        type_list<signed long long, null_type> > > > >



    /*
     * These are acutally typedef used in programs.
     * 
     * Nomenclature is [u]intN where u if present means unsigned, N is the 
     * number of bits in the integer
     *
     * find_type is used simply by giving first a type_list then the number of 
     * bits to search for.
     *
     * NB. Each type in the type list must had specified the template 
     * numeric_limits as it is used to compute the type len in (binary) digit.
     */
    typedef find_type<UNSIGNED_TYPES, 8>::type  uint8;
    typedef find_type<UNSIGNED_TYPES, 16>::type uint16;
    typedef find_type<UNSIGNED_TYPES, 32>::type uint32;
    typedef find_type<UNSIGNED_TYPES, 64>::type uint64;

    typedef find_type<SIGNED_TYPES, 7>::type    int8;
    typedef find_type<SIGNED_TYPES, 15>::type   int16;
    typedef find_type<SIGNED_TYPES, 31>::type   int32;
    typedef find_type<SIGNED_TYPES, 63>::type   int64;

}
użytkownik781847
źródło
0
unsigned char bits = sizeof(X) << 3;

gdzie Xjest char, int, longetc .. daje rozmiar Xw bitach.

użytkownik3154672
źródło
1
char nie zawsze ma 8 bitów, więc twoje wyrażenie nie będzie działać na architekturach z charakterem innym niż 8-bit . sizeof(type)*CHAR_BITTrzyma tylko
phuclv
Nawet jeśli CHAR_BITgwarantowane jest 8 bitów, << 3jest jedynie zaciemnionym sposobem pisania * 8lub * CHAR_BIT.
Keith Thompson
0

Od Alex B Standard C ++ nie określa wielkości typów całkowych w bajtach, ale określa minimalne zakresy, które muszą być w stanie pomieścić. Możesz określić minimalny rozmiar w bitach z wymaganego zakresu. Na podstawie tego można wywnioskować minimalny rozmiar w bajtach oraz wartość makra CHAR_BIT, która definiuje liczbę bitów w bajcie (na wszystkich mało znanych platformach jest to 8 i nie może być mniejsza niż 8).

Dodatkowym ograniczeniem dla znaku jest to, że jego rozmiar wynosi zawsze 1 bajt lub bit CHAR_BIT (stąd nazwa).

Minimalne zakresy wymagane przez standard (strona 22) to:

i zakresy typów danych w MSDN:

podpisany znak: od -127 do 127 (uwaga, nie od -128 do 127; to dotyczy platform z uzupełnieniem 1) znak bez znaku: od 0 do 255 znak „zwykły”: od -127 do 127 lub od 0 do 255 (w zależności od domyślnej sygnatury znaku) podpisany krótki: od -32767 do 32767 bez znaku krótki: od 0 do 65535 podpisany int: -32767 do 32767 niepodpisany int: 0 do 65535 podpisany długi: -2147483647 do 2147483647 niepodpisany długi: od 0 do 4294967295 podpisany długi długi: -9223372036854775807 do 9223372036854775807 niepodpisany 0 do 18446744073709551615 Implementacja C ++ (lub C) może definiować rozmiar typu w bajtach sizeof (type) do dowolnej wartości, o ile

wyrażenie sizeof (typ) * CHAR_BIT ocenia na liczbę bitów wystarczającą do zawarcia wymaganych zakresów, a kolejność typów jest nadal ważna (np. sizeof (int) <= sizeof (long)). Rzeczywiste zakresy specyficzne dla implementacji można znaleźć w nagłówku w C lub w C ++ (lub jeszcze lepiej w szablonie std :: numeric_limits w nagłówku).

Na przykład, w ten sposób znajdziesz maksymalny zasięg dla int:

DO:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

Jest to jednak poprawne, masz rację mówiąc, że: char: 1 bajt krótki: 2 bajty int: 4 bajty długie: 4 bajty zmiennoprzecinkowe: 4 bajty podwójne: 8 bajtów

Ponieważ architektury 32-bitowe są nadal domyślne i najczęściej używane, i zachowały te standardowe rozmiary od czasów sprzed 32 bitów, kiedy pamięć była mniej dostępna, a dla kompatybilności wstecznej i standaryzacji pozostała taka sama. Nawet systemy 64-bitowe zwykle z nich korzystają i mają rozszerzenia / modyfikacje. Więcej informacji na ten temat:

http://en.cppreference.com/w/cpp/language/types

JCoder
źródło
0

Zauważam, że wszystkie inne odpowiedzi tutaj koncentrowały się prawie wyłącznie na typach integralnych, podczas gdy pytający pytał także o zmiennoprzecinkowe.

Nie sądzę, aby wymagał tego standard C ++, ale kompilatory dla najpopularniejszych platform w dzisiejszych czasach generalnie stosują się do standardu IEEE754 pod względem liczb zmiennoprzecinkowych. Ten standard określa cztery typy binarnych liczb zmiennoprzecinkowych (a także niektóre formaty BCD, których nigdy nie widziałem w kompilatorach C ++):

  • Połowa precyzji (binarnie 16) - 11-bitowe znaczenie, wykładniczy zakres -14 do 15
  • Pojedyncza precyzja (binarna32) - 24-bitowe znaczenie, wykładniczy zakres -126 do 127
  • Podwójna precyzja (binarny64) - 53-bitowe znaczenie, wykładniczy zakres -1022 do 1023
  • Czterokrotna precyzja (binarna 128) - znaczenie 113-bitowe, zakres wykładniczy -16382 do 16383

Jak zatem mapuje się na typy C ++? Zasadniczo floatwykorzystuje pojedynczą precyzję; tak więc sizeof(float) = 4. Następnie doubleużywa podwójnej precyzji (uważam, że to jest źródło nazwy double) ilong double może to być podwójna lub poczwórna precyzja (w moim systemie jest czterokrotna, ale w systemach 32-bitowych może być podwójna). Nie znam żadnych kompilatorów, które oferują zmiennoprzecinkowe połowy precyzji.

Podsumowując, jest to zwykle:

  • sizeof(float) = 4
  • sizeof(double) = 8
  • sizeof(long double) = 8 lub 16
celticminstrel
źródło
Zabawne, że doszedłem do tego pytania w ramach zastanawiania się, dlaczego Jeff używa więcej bajtów, niż musi.
Aniruddha Varma
-2

Możesz używać zmiennych dostarczanych przez biblioteki takie jak OpenGL , Qt itp.

Na przykład Qt zapewnia qint8 (gwarantowane 8-bitowe na wszystkich platformach obsługiwanych przez Qt), qint16, qint32, qint64, quint8, quint16, quint32, quint64 itp.

Lawand
źródło
1
Nie odpowiada na pytanie
EvilTeach,
-8

Na komputerze 64-bitowym:

int: 4
long: 8
long long: 8
void*: 8
size_t: 8
użytkownik 2826084
źródło
2
Na niektórych komputerach 64-bitowych intjest 8 bajtów, ale drugi nie jest gwarantowany. Nic nie mówi, że charpowinno to być tylko 8 bitów. Dozwolone jest to, sizeof(void*)==4mimo że ma 64 bity.
skyking
-10

Istnieją cztery typy liczb całkowitych w zależności od rozmiaru:

  • krótka liczba całkowita: 2 bajty
  • długa liczba całkowita: 4 bajty
  • długa długa liczba całkowita: 8 bajtów
  • liczba całkowita: zależy od kompilatora (16-bitowy, 32-bitowy lub 64-bitowy)
ricky
źródło
11
Fałsz, wszystkie zależą od architektury, a minimalne zakresy opisano w jednej z pozostałych odpowiedzi. Nic nie zatrzyma implementację mieć short, inti longwszystkie 32-bitowe liczby całkowite.
Matteo Italia,
Nie użyłeś nawet prawidłowych nazw dla typów. Nazwy używają słowa kluczowego int, a nie słowa „liczba całkowita”.
Keith Thompson,