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

173

W kilku przykładach C ++ widzę użycie typu, w size_tktórym użyłbym prostego int. Jaka jest różnica i dlaczego size_tpowinno być lepiej?

tunnuz
źródło
3
Aby zapoznać się z rzeczywistym przykładem, w którym nie są wymienne, zobacz pytanie, które zadałem wcześniej: stackoverflow.com/questions/645168/ ...
Tyler McHenry

Odpowiedzi:

153

Z przyjaznej Wikipedii :

Pliki nagłówkowe stdlib.h i stddef.h definiują typ danych o nazwie size_t, który jest używany do reprezentowania rozmiaru obiektu. Funkcje biblioteczne, które przyjmują rozmiary, oczekują, że będą one typu size_t, a operator sizeof oblicza rozmiar_t.

Rzeczywisty typ size_t jest zależny od platformy; częstym błędem jest założenie, że size_t jest tym samym, co unsigned int, co może prowadzić do błędów w programowaniu, zwłaszcza gdy coraz bardziej rozpowszechnione są architektury 64-bitowe.

Sprawdź też, dlaczego rozmiar_t ma znaczenie

Joao da Silva
źródło
76
A więc co to jest size_t?
NDEthos
8
@NDEthos To zależy! W tym miejscu Linux /usr/include/stdlib.hpobiera definicję skąd /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.hi tam jest ona ustawiona domyślnie, long unsigned intchyba że inny plik nagłówkowy mówi inaczej.
David Tonhofer
1
Potwierdzam, że funkcja size_t do int tuncation jest niebezpieczna . To może być nie na temat, ale jak napisać samą łatkę, aby naprawić tego rodzaju błędy, które pojawiają się tysiące razy w jądrze Linuksa?
user2284570
36

size_t to typ używany do reprezentowania rozmiarów (jak sugeruje jego nazwa). Jego platforma (a nawet potencjalnie implementacja) jest zależna i powinien być używany tylko w tym celu. Oczywiście, reprezentując rozmiar, size_t jest bez znaku. Wiele funkcji z biblioteki standardowej, w tym malloc, sizeof i różne funkcje operacji na łańcuchach, używa size_t jako typu danych.

Wartość int jest domyślnie podpisywana i chociaż jego rozmiar jest również zależny od platformy, na większości nowoczesnych maszyn będzie to stały 32-bitowy (i chociaż size_t to 64 bity w architekturze 64-bitowej, na tych architekturach wartość int pozostaje 32-bitowa).

Podsumowując: użyj size_t, aby przedstawić rozmiar obiektu i int (lub long) w innych przypadkach.

Axelle Ziegler
źródło
12

size_tTypu określa się jako unsigned integralną typu sizeofoperatora. W prawdziwym świecie często widzisz intdefinicję jako 32 bity (dla kompatybilności wstecznej), ale size_tzdefiniowaną jako 64 bity (więc możesz zadeklarować tablice i struktury o rozmiarze większym niż 4 GiB) na platformach 64-bitowych. Jeśli a long intjest również 64-bitowy, nazywa się to konwencją LP64; jeśli long intma 32 bity, ale long long intwskaźniki mają 64 bity, to jest LLP64. Możesz również otrzymać odwrotną stronę, program, który używa 64-bitowych instrukcji prędkości, ale 32-bitowych wskaźników do oszczędzania pamięci. Ponadto intjest podpisany i size_tniepodpisany.

Historycznie istniało wiele innych platform, na których adresy były szersze lub krótsze niż natywny rozmiar int. W rzeczywistości w latach 70. i na początku 80. było to bardziej powszechne niż nie: wszystkie popularne 8-bitowe mikrokomputery miały 8-bitowe rejestry i 16-bitowe adresy, a przejście między 16 a 32 bitami również tworzyło wiele maszyn, które mieli adresy szersze niż ich rejestry. Czasami wciąż widzę tutaj pytania o Borland Turbo C dla MS-DOS, którego tryb ogromnej pamięci miał 20-bitowe adresy przechowywane w 32 bitach na 16-bitowym procesorze (ale które mogą obsługiwać 32-bitowy zestaw instrukcji 80386); Motorola 68000 miała 16-bitową jednostkę ALU z 32-bitowymi rejestrami i adresami; istniały komputery mainframe IBM z 15-bitowymi, 24-bitowymi lub 31-bitowymi adresami. Nadal widzisz różne rozmiary ALU i magistrali adresowej w systemach wbudowanych.

Za każdym razem, gdy intjest mniejszy niż size_ti próbujesz zapisać rozmiar lub przesunięcie bardzo dużego pliku lub obiektu w pliku unsigned int, istnieje możliwość, że może się przepełnić i spowodować błąd. W przypadku znaku intistnieje również możliwość uzyskania liczby ujemnej. Jeśli intlub unsigned intjest szerszy, program będzie działał poprawnie, ale marnuje pamięć.

Jeśli chcesz mieć możliwość przenoszenia, na ogół powinieneś używać odpowiedniego typu do tego celu. Wiele osób poleci używanie matematyki ze znakiem zamiast bez znaku (aby uniknąć nieprzyjemnych, subtelnych błędów, takich jak 1U < -3). W tym celu Standard definiuje biblioteczne ptrdiff_tw <stddef.h>tak podpisanej typu wyniku odjęcia wskaźnik od drugiego.

To powiedziawszy, obejściem może być sprawdzenie granic wszystkich adresów i przesunięć względem INT_MAXi albo 0lub INT_MINodpowiednio, i włączenie ostrzeżeń kompilatora o porównywaniu podpisanych i niepodpisanych ilości na wypadek, gdybyś je pominął. Zawsze powinieneś zawsze sprawdzać dostęp do tablicy pod kątem przepełnienia w C.

Davislor
źródło
8

Dzieje się tak, ponieważ size_t może być czymkolwiek innym niż int (może być strukturą). Chodzi o to, że oddziela swoje zadanie od typu podstawowego.

graham.reeds
źródło
8
Myślę, że size_t faktycznie jest gwarantowanym aliasem dla liczby całkowitej bez znaku, więc nie może to być struktura. Jednak w tej chwili nie mam pod ręką odniesienia, aby to potwierdzić.
zrelaksuj się
9
@unwind: C99: TC3, 7,17 §2
Christoph
1
@danio Dlaczego tak jest? Czy możesz wyjaśnić?
Rüppell's Vulture
2
Nie linkowałbym do cplusplus, gdybym był tobą! Jeśli nie możesz zacytować rozdziału, wersetu, akapitu i wiersza, to wszystko to tylko pogłoski! :-)
graham.reeds
1
size_tjest określony jako typ liczby całkowitej bez znaku . C11 §6.5.3.4 5 „Wartość wyniku obu operatorów ( sizeof _Alignof) jest zdefiniowana w ramach implementacji, a jego typ (liczba całkowita bez znaku) to size_t,”.
chux - Przywróć Monikę
-1

Definicja SIZE_Tznajduje się na: https://msdn.microsoft.com/en-us/library/cc441980.aspx i https://msdn.microsoft.com/en-us/library/cc230394.aspx

Wklejanie tutaj wymaganych informacji:

SIZE_Tjest ULONG_PTRreprezentowanie maksymalną liczbę bajtów, do którego wskaźnik może wskazywać.

Ten typ jest deklarowany w następujący sposób:

typedef ULONG_PTR SIZE_T;

A ULONG_PTRto typ długi bez znaku, używany do dokładności wskaźnika. Jest używany podczas rzutowania wskaźnika na długi typ w celu wykonania arytmetyki wskaźnika.

Ten typ jest deklarowany w następujący sposób:

typedef unsigned __int3264 ULONG_PTR;
sundar
źródło
2
SIZE_Tnie jest size_t, o co pytał OP.
ikegami
2
To rozszerzenie firmy Microsoft, a nie część standardowego języka.
Davislor,
SIZE_Tjest zupełnie inny niż size_t. Nie możesz zadeklarować zmiennej typu SIZE_T.
calocedrus