Vedo variabili definite con questo tipo ma non so da dove provenga, né qual è il suo scopo. Perché non utilizzare int o unsigned int? (E gli altri tipi "simili"? Void_t, ecc.).
Vedo variabili definite con questo tipo ma non so da dove provenga, né qual è il suo scopo. Perché non utilizzare int o unsigned int? (E gli altri tipi "simili"? Void_t, ecc.).
Risposte:
Da Wikipedia
I file di intestazione
stdlib.h
estddef.h
definiscono un tipo di dati chiamatosize_t
1 che viene utilizzato per rappresentare la dimensione di un oggetto. Le funzioni di libreria che accettano dimensioni si aspettano che siano di tiposize_t
e l'operatore sizeof restituiscesize_t
.Il tipo effettivo di
size_t
dipende dalla piattaforma; un errore comune è presumere chesize_t
sia uguale a unsigned int, che può portare a errori di programmazione, 2 in particolare quando le architetture a 64 bit diventano più diffuse.
I seguenti tipi e macro sono definiti nell'intestazione standard
stddef.h
<Snip>
size_t
che è il tipo intero senza segno del risultato dell'operatore sizeof
int
e i unsigned int
tipi sono 32 bit, mentre size_t è 64 bit.
Secondo size_t, la descrizione su en.cppreference.com size_t
è definita nelle seguenti intestazioni:
std::size_t
...
Defined in header <cstddef>
Defined in header <cstdio>
Defined in header <cstring>
Defined in header <ctime>
Defined in header <cwchar>
size_t
è il tipo intero senza segno del risultato dell'operatore sizeof (ISO C99 sezione 7.17.)
L' sizeof
operatore restituisce la dimensione (in byte) del suo operando, che può essere un'espressione o il nome tra parentesi di un tipo. La dimensione è determinata dal tipo di operando. Il risultato è un numero intero. Il valore del risultato è definito dall'implementazione e il suo tipo (un tipo intero senza segno) è size_t
(ISO C99 Sezione 6.5.3.4.)
In pratica size_t
rappresenta il numero di byte che puoi indirizzare. Sulla maggior parte delle architetture moderne negli ultimi 10-15 anni sono stati 32 bit che hanno anche avuto le dimensioni di un int senza segno. Tuttavia ci stiamo spostando verso l'indirizzamento a 64 bit mentre uint
molto probabilmente rimarrà a 32 bit (la sua dimensione non è garantita nello standard c ++). Per rendere il tuo codice che dipende dalla dimensione della memoria portabile attraverso le architetture dovresti usare un file size_t
. Ad esempio cose come le dimensioni degli array dovrebbero sempre usare size_t
's. Se guardi i contenitori standard ::size()
restituisce sempre un file size_t
.
Si noti inoltre che Visual Studio ha un'opzione di compilazione che può verificare questi tipi di errori denominati "Rileva problemi di portabilità a 64 bit".
In questo modo sai sempre qual è la taglia, perché un tipo specifico è dedicato alle taglie. La stessa domanda mostra che può essere un problema: è un int
o uno unsigned int
? Inoltre, qual è la grandezza ( short
, int
,long
, etc.)?
Poiché è stato assegnato un tipo specifico, non devi preoccuparti della lunghezza o della firma.
La definizione effettiva può essere trovata nella libreria di riferimento C ++ , che dice:
Genere:
size_t
(tipo integrale senza segno)Intestazione:
<cstring>
size_t
corrisponde al tipo di dati integrale restituito dall'operatore del linguaggiosizeof
ed è definito nel file<cstring>
file di intestazione (tra gli altri) come tipo integrale senza segno.In
<cstring>
, è usato come il tipo di parametronum
nelle funzionimemchr
,memcmp
,memcpy
,memmove
,memset
,strncat
,strncmp
,strncpy
estrxfrm
, che in ogni caso è utilizzato per specificare il numero massimo di byte o caratteri la funzione deve incidere.È anche usato come tipo cambio
strcspn
,strlen
,strspn
estrxfrm
per le dimensioni e lunghezze ritorno.
size_t dovrebbe essere definito nelle intestazioni della libreria standard. Nella mia esperienza, di solito è semplicemente un typedef a unsigned int. Il punto, però, è che non deve essere così. Tipi come size_t consentono al fornitore di librerie standard la libertà di modificare i propri tipi di dati sottostanti, se appropriato per la piattaforma. Se presumi che size_t sia sempre unsigned int (tramite casting, ecc.), Potresti incorrere in problemi in futuro se il tuo fornitore cambia size_t per essere, ad esempio, un tipo a 64 bit. È pericoloso presumere qualcosa su questo o qualsiasi altro tipo di libreria per questo motivo.
Non ho familiarità con void_t
se non come risultato di una ricerca su Google (è utilizzato in una vmalloc
libreria da Kiem-Phong Vo presso AT&T Research - sono sicuro che sia usato anche in altre biblioteche).
I vari typedef xxx_t sono usati per astrarre un tipo da una particolare implementazione definita, poiché i tipi concreti usati per certe cose potrebbero differire da una piattaforma all'altra. Per esempio:
Void_t
astrae il tipo di puntatore restituito dalle vmalloc
routine della libreria perché è stato scritto per funzionare su sistemi che precedono ANSI / ISO C dove ilvoid
parola chiave potrebbe non esistere. Almeno questo è quello che immagino.wchar_t
astrae il tipo usato per i caratteri larghi poiché su alcuni sistemi sarà un tipo a 16 bit, su altri sarà un tipo a 32 bit.Quindi, se scrivi il tuo codice per la gestione dei caratteri per usare il wchar_t
tipo invece di, diciamo unsigned short
, quel codice sarà presumibilmente più portabile su varie piattaforme.
Nei programmi minimalisti in cui una size_t
definizione non è stata caricata "per caso" in alcuni include ma ne ho ancora bisogno in qualche contesto (ad esempio per accedere std::vector<double>
), quindi utilizzo quel contesto per estrarre il tipo corretto. Per esempiotypedef std::vector<double>::size_type size_t
.
(Circondare con namespace {...}
se necessario per limitare l'ambito.)
Quanto a "Perché non utilizzare int o unsigned int?", Semplicemente perché semanticamente è più significativo non farlo. C'è la ragione pratica per cui può essere, diciamo, typedef
d come un int
e poi aggiornato a un long
secondo, senza che nessuno debba cambiare il proprio codice, ovviamente, ma più fondamentalmente di che un tipo dovrebbe essere significativo. Per semplificare enormemente, una variabile di tipo size_t
è adatta e utilizzata per contenere le dimensioni delle cose, proprio come time_t
è adatta per contenere valori temporali. Il modo in cui questi vengono effettivamente implementati dovrebbe essere abbastanza correttamente compito dell'implementazione. Rispetto alla semplice chiamata di tutto int
, l'uso di nomi di tipo significativi come questo aiuta a chiarire il significato e l'intento del tuo programma, proprio come fa qualsiasi ricco insieme di tipi.