In diversi esempi C ++ vedo un uso del tipo size_t dove avrei usato un int semplice. Qual è la differenza e perché size_t dovrebbe essere migliore?
Dalla Wikipedia amichevole :
I file di intestazione stdlib.h e stddef.h definiscono un tipo di dati chiamato size_t che viene utilizzato per rappresentare la dimensione di un object. Le funzioni di libreria che prendono dimensioni si aspettano che siano di tipo size_t e l’operatore sizeof valuti a size_t.
Il tipo effettivo di size_t dipende dalla piattaforma; un errore comune è quello di assumere size_t è lo stesso di unsigned int, che può portare a errori di programmazione, in particolare quando le architetture a 64 bit diventano più prevalenti.
Inoltre, controlla Perché size_t è importante
size_t è il tipo utilizzato per rappresentare le dimensioni (come indica il nome). La sua piattaforma (e anche potenzialmente l’implementazione) dipende e dovrebbe essere utilizzata solo per questo scopo. Ovviamente, rappresentando una dimensione, size_t non è firmata. Molte funzioni di stdlib, tra cui malloc, sizeof e varie funzioni per le operazioni su stringhe usano size_t come un tipo di dati.
Un int è firmato per impostazione predefinita, e anche se la sua dimensione dipende anche dalla piattaforma, sarà un 32 bit fisso sulla maggior parte delle macchine moderne (e sebbene size_t sia 64 bit su architettura a 64 bit, int resterà a 32 bit di lunghezza su quelle architetture).
Per riassumere: usa size_t per rappresentare la dimensione di un object e int (o long) negli altri casi.
È perché size_t può essere qualsiasi cosa diversa da un int (forse una struct). L’idea è che disaccoppia il suo lavoro dal tipo sottostante.
Il tipo size_t
è definito come il tipo integrale senza segno dell’operatore sizeof
. Nel mondo reale, vedrete spesso int
definito come 32 bit (per retrocompatibilità) ma size_t
definito come 64 bit (in modo da poter dichiarare array e strutture con dimensioni superiori a 4 GiB) su piattaforms a 64 bit. Se un long int
è anche 64-bit, questo è chiamato la convenzione LP64; se long int
è 32 bit ma long long int
e pointers 64 bit, è LLP64. Si potrebbe anche ottenere il contrario, un programma che utilizza istruzioni a 64 bit per la velocità, ma i puntatori a 32 bit per risparmiare memoria. Inoltre, int
è firmato e size_t
non è firmato.
C’erano storicamente un certo numero di altre piattaforms in cui gli indirizzi erano più larghi o più brevi della dimensione nativa di int
. In effetti, negli anni ’70 e all’inizio degli anni ’80, questo era più comune: tutti i popolari microcomputer a 8 bit avevano registri a 8 bit e indirizzi a 16 bit, e la transizione tra 16 e 32 bit produceva anche molte macchine che aveva indirizzi più ampi dei loro registri. Di tanto in tanto vedo ancora domande su Borland Turbo C per MS-DOS, la cui modalità di memoria enorme aveva indirizzi a 20 bit memorizzati in 32 bit su una CPU a 16 bit (ma che poteva supportare il set di istruzioni a 32 bit dell’80386); il Motorola 68000 aveva un ALU a 16 bit con registri e indirizzi a 32 bit; c’erano mainframe IBM con indirizzi 15-bit, 24-bit o 31-bit. È inoltre ansible vedere diverse dimensioni di ALU e bus di indirizzo nei sistemi incorporati.
Ogni volta che int
è minore di size_t
e si tenta di memorizzare la dimensione o l’offset di un file o di un object molto grande in un unsigned int
, esiste la possibilità che possa traboccare e causare un bug. Con un int
, c’è anche la possibilità di ottenere un numero negativo. Se un int
o unsigned int
è più ampio, il programma funzionerà correttamente ma sprecherà memoria.
In genere, se si desidera la portabilità, è necessario utilizzare il tipo corretto per lo scopo. Un sacco di persone raccomandano di usare la matematica firmata anziché quella non firmata (per evitare bug fastidiosi come 1U < -3
). A tale scopo, la libreria standard definisce ptrdiff_t
in
come tipo firmato del risultato della sottrazione di un puntatore da un altro.
Detto questo, una soluzione alternativa potrebbe essere quella di controllare tutti gli indirizzi e gli offset rispetto a INT_MAX
e 0
o INT_MIN
come appropriato, e triggersre gli avvisi del compilatore sul confronto delle quantità firmate e non firmate nel caso in cui manchi qualsiasi. Dovresti sempre, sempre, controllare sempre gli accessi al tuo array per overflow in C comunque.
La definizione di SIZE_T
è disponibile all’indirizzo: https://msdn.microsoft.com/en-us/library/cc441980.aspx e https://msdn.microsoft.com/en-us/library/cc230394.aspx
Incollare qui le informazioni richieste:
SIZE_T
è un ULONG_PTR
rappresenta il numero massimo di byte a cui un puntatore può puntare.
Questo tipo è dichiarato come segue:
typedef ULONG_PTR SIZE_T;
Un ULONG_PTR
è un tipo lungo senza segno utilizzato per la precisione del puntatore. Viene utilizzato quando si esegue il cast di un puntatore a un tipo lungo per eseguire l’aritmetica del puntatore.
Questo tipo è dichiarato come segue:
typedef unsigned __int3264 ULONG_PTR;