Lo standard C garantisce che size_t
è un tipo che può contenere qualsiasi indice di array. Ciò significa che, logicamente, size_t
dovrebbe essere in grado di contenere qualsiasi tipo di puntatore. Ho letto su alcuni siti che ho trovato su Google che questo è legale e / o dovrebbe sempre funzionare:
void *v = malloc(10);
size_t s = (size_t) v;
Quindi, in C99, lo standard ha introdotto i tipi intptr_t
e uintptr_t
, che sono tipi firmati e non firmati garantiti per essere in grado di contenere i puntatori:
uintptr_t p = (size_t) v;
Quindi qual è la differenza tra l'utilizzo di size_t
e uintptr_t
? Entrambi sono senza segno ed entrambi dovrebbero essere in grado di contenere qualsiasi tipo di puntatore, quindi sembrano funzionalmente identici. C'è qualche vero motivo convincente da usare uintptr_t
(o meglio ancora, a void *
) piuttosto che a size_t
, oltre alla chiarezza? In una struttura opaca, in cui il campo sarà gestito solo da funzioni interne, c'è qualche motivo per non farlo?
Allo stesso modo, ptrdiff_t
è stato un tipo con segno in grado di contenere le differenze di puntatore e quindi in grado di contenere la maggior parte di qualsiasi puntatore, quindi come si distingue intptr_t
?
Tutti questi tipi non servono sostanzialmente versioni banalmente diverse della stessa funzione? Se no, perché? Cosa non posso fare con uno di loro che non posso fare con un altro? In tal caso, perché C99 ha aggiunto due tipi essenzialmente superflui alla lingua?
Sono disposto a ignorare i puntatori alle funzioni, poiché non si applicano al problema attuale, ma sono libero di menzionarli, poiché ho il sospetto che saranno fondamentali per la risposta "corretta".
size_t
euintptr_t
ma che dire diptrdiff_t
eintptr_t
- entrambi non sarebbero in grado di memorizzare lo stesso intervallo di valori su quasi tutte le piattaforme? Perché avere tipi interi di dimensioni puntatore sia firmate che non firmate, in particolare septrdiff_t
serve già allo scopo di un tipo intero di dimensioni puntatore firmato.