Qual è la differenza tra size_t e int in C ++?


173

In diversi esempi di C ++ vedo un uso del tipo in size_tcui avrei usato un semplice int. Qual è la differenza e perché size_tdovrebbe essere migliore?


3
Per un esempio reale in cui non sono intercambiabili, vedere una domanda che ho posto in precedenza: stackoverflow.com/questions/645168/…
Tyler McHenry,

Risposte:


153

Da l'amichevole Wikipedia :

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 oggetto. Le funzioni di libreria che accettano dimensioni si aspettano che siano di tipo size_t e l'operatore sizeof restituisce size_t.

Il tipo effettivo di size_t dipende dalla piattaforma; un errore comune è supporre che size_t sia uguale a unsigned int, il che può portare a errori di programmazione, in particolare quando le architetture a 64 bit diventano più diffuse.

Inoltre, controlla Perché size_t è importante


76
E quindi, cos'è size_t?
NDEthos,

8
@NDEthos Dipende! Su questo qui Linux /usr/include/stdlib.hottiene la definizione /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.he in essa è predefinita a long unsigned intmeno che qualche altro file di intestazione non dica diversamente.
David Tonhofer,

1
Confermo che size_t a inizio è pericoloso . Questo potrebbe essere fuori tema, ma come scrivere una patch da sola per correggere quel tipo di errori quando si verifica migliaia di volte nel kernel di Linux?
user2284570

36

size_t è il tipo utilizzato per rappresentare le dimensioni (come suggerisce 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 è firmato. Molte funzioni stdlib, tra cui malloc, sizeof e varie funzioni operative delle stringhe utilizzano size_t come tipo di dati.

Un int è firmato per impostazione predefinita e anche se le sue dimensioni dipendono anche dalla piattaforma, saranno 32 bit fissi sulla maggior parte delle macchine moderne (e sebbene size_t sia 64 bit su un'architettura a 64 bit, int rimarrà a 32 bit su quelle architetture).

Per riassumere: usa size_t per rappresentare la dimensione di un oggetto e int (o long) in altri casi.


12

Il size_ttipo è definito come il tipo integrale senza segno sizeofdell'operatore. Nel mondo reale, vedrai spesso intdefiniti come 32 bit (per compatibilità con le versioni precedenti) ma size_tdefiniti come 64 bit (in modo da poter dichiarare matrici e strutture di dimensioni superiori a 4 GiB) su piattaforme a 64 bit. Se a long intè anche 64 bit, questa è chiamata convenzione LP64; se long intè 32 bit ma i long long intpuntatori sono 64 bit, è LLP64. Potresti anche ottenere il contrario, un programma che utilizza istruzioni a 64 bit per la velocità, ma puntatori a 32 bit per risparmiare memoria. Inoltre, intè firmato e size_tnon firmato.

Storicamente c'erano diverse altre piattaforme in cui gli indirizzi erano più larghi o più brevi delle dimensioni native di int. In effetti, negli anni '70 e all'inizio degli anni '80, questo era più comune che no: 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 avevano 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 potevano 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 a 15, 24 o 31 bit. Si vedono anche diverse ALU e dimensioni del bus di indirizzo nei sistemi integrati.

Ogni volta che intè più piccolo di size_te si tenta di memorizzare la dimensione o l'offset di un file o oggetto molto grande in un unsigned int, c'è la possibilità che potrebbe traboccare e causare un bug. Con un int, c'è anche la possibilità di ottenere un numero negativo. Se un into unsigned intè più ampio, il programma verrà eseguito correttamente ma sprecherà memoria.

In genere è necessario utilizzare il tipo corretto per lo scopo se si desidera la portabilità. Molte persone raccomandano di usare la matematica firmata anziché quella non firmata (per evitare bug cattivi e sottili come 1U < -3). A tal fine, le definisce libreria standard ptrdiff_tin <stddef.h>quanto il tipo firmata del risultato della sottrazione un puntatore da un altro.

Detto questo, una soluzione alternativa potrebbe essere quella di controllare i limiti di tutti gli indirizzi e gli offset rispetto ae INT_MAXuno 0o INT_MINcome appropriato e attivare gli avvisi del compilatore sul confronto tra quantità firmate e non firmate in caso di perdita. In ogni caso, dovresti sempre, sempre, controllare sempre gli accessi al tuo array per overflow in C.


8

È perché size_t può essere qualcosa di diverso da un int (forse uno struct). L'idea è che disaccoppia il suo lavoro dal tipo sottostante.


8
Penso che size_t sia effettivamente garantito come alias per un numero intero senza segno, quindi non può essere una struttura. Tuttavia, non ho un riferimento utile per eseguire il backup di questo momento.
Rilassati il

9
@unwind: C99: TC3, 7.17 §2
Christoph,

1
@danio Perché è così? puoi spiegare?
Rüppell's Vulture

2
Non vorrei collegarmi a cplusplus se fossi in te! Se non puoi citare capitolo, versetto, paragrafo e riga, allora è tutto solo sentito! :-)
graham.reeds

1
size_tè specificato come tipo intero senza segno . C11 §6.5.3.4 5 "Il valore del risultato di entrambi gli operatori ( sizeof _Alignof) è definito dall'implementazione e il suo tipo (un tipo intero senza segno) è size_t,".
chux - Ripristina Monica il

-1

La definizione di SIZE_Tsi trova su: https://msdn.microsoft.com/en-us/library/cc441980.aspx e https://msdn.microsoft.com/en-us/library/cc230394.aspx

Incollando qui le informazioni richieste:

SIZE_Tè una ULONG_PTRrappresentazione del numero massimo di byte a cui può puntare un puntatore.

Questo tipo è dichiarato come segue:

typedef ULONG_PTR SIZE_T;

A ULONG_PTRè un tipo lungo senza segno utilizzato per la precisione del puntatore. Viene usato quando si lancia un puntatore su un tipo lungo per eseguire l'aritmetica del puntatore.

Questo tipo è dichiarato come segue:

typedef unsigned __int3264 ULONG_PTR;

2
SIZE_Tnon è size_tquello che l'OP ha chiesto.
ikegami,

2
Questa è un'estensione di Microsoft, non parte del linguaggio standard.
Davislor,

SIZE_Tè totalmente diverso da size_t. Non puoi dichiarare una variabile di tipo SIZE_T.
Calocedrus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.