La portabilità è sempre all'interno di alcune piattaforme. C non è un linguaggio perfettamente portatile; è possibile costruire macchine su cui non è possibile implementare C (o su cui non è possibile implementare C ragionevolmente bene). Quindi la questione della portabilità è sempre una delle varie piattaforme supportate.
Usando C, supportate alcuni sottoinsiemi di piattaforme che hanno compilatori C funzionanti. Ovviamente. Ma quello che fai con C può restringere il supporto.
If your code depends on the sizeof(T)
of an integral type, in order to keep it portable you should use the types in stdint.h
like uint8_t
or uint32_t
Se scrivi un codice che dipende dalla dimensione di un tipo, non stai scrivendo un codice che sia portatile come C stesso. Come sei stato informato, uint8_t
e tali tipi sono non richiesti dallo standard C. Con qualsiasi standard C; sono funzioni facoltative di C99 e C11. E C ++ 11 e versioni successive, nel caso ve lo stiate chiedendo.
Ma portatile "per quanto riguarda lo standard" non è necessariamente la fine della portabilità. Dopo tutto ci sono molte piattaforme che possono e supportano questi tipi. Il tuo codice può essere trasferito su tali piattaforme.
Ciò di cui ti stai veramente preoccupando non è tanto la dipendenza dai tipi di dimensioni. Ciò di cui sei stato avvisato è affidarsi alle dimensioni del tipo . È quello che limita le tue piattaforme, perché C non definisce le dimensioni del testo. C consente alle singole piattaforme di farlo.
Pertanto, il codice che si basa sull'avere un tipo intero veloce a 32 bit è per sua stessa natura non portabile su piattaforme che non dispongono di tali elementi. A titolo di esempio, Vulkan si autoproclama come API grafica multipiattaforma. E questo è. Ma Vulkan definisce tutti i suoi tipi in termini di tipi interi di stdint.h
. Perché?
Perché se una piattaforma non può supportarli loro , la piattaforma non può supportare il periodo Vulkan. Quindi non ha senso fingere che Vulkan possa funzionare su qualsiasi cosa C possa.
Questo non è sbagliato; sta semplicemente impostando i tuoi limiti in base alle esigenze del tuo codice. Spesso invii strutture dati direttamente da e verso Vulkan, e devi essere in grado di far corrispondere ciò che le implementazioni si aspettano / richiedono. Quindi la tua piattaforma C deve supportare tipi che possano combaciare con questi.
Allo stesso tempo, se non stai facendo qualcosa che richiede esplicitamente una dimensione specifica di numero intero, allora stai facendo a te stesso un disservizio usando un tipo intero di dimensioni esplicite quando un int
farebbe. I tipi int_leastXX_t
sono obbligatori e possono gestire la maggior parte dei problemi relativi agli intervalli interi.
In what other way can I convince this guy that if you use the basic types like int
or short
, your code will not be portable?
L'uso di questi tipi sarà non portabile solo se fai cose non portabili con loro.
Ad esempio, la manipolazione dei bit è ben definita in C. Il numero specifico di bit in int
non lo è. Quindi il seguente codice:
unsigned int i = 1 << 19;
È perfetto, ben definito ... a patto che sizeof(unsigned int)
sia 20 bit o più su quella piattaforma. Quindi qualsiasi piattaforma in cui questo è vero andrà bene.
Al contrario:
uint32_t i = 1 << 19;
È solo un codice ben definito se la piattaforma supporta uint32_t
. Se ha una dimensione di byte insolita (9 e 18 bit non sono dimensioni di byte sconosciute), quindi non può supportare uint32_t
. E quindi quel codice non può funzionare. Ma potrebbe aver funzionato per il primo caso, perché int
poteva avere una dimensione di 36 bit.
Limitando te stesso ai tipi di numeri interi specifici, ti limiti anche alle piattaforme che supportano questi tipi di numeri interi. Se usi i tipi interi fondamentali, sei limitato alle piattaforme in cui tali tipi sono "abbastanza grandi" per qualsiasi cosa li usi.
Quindi qual è il più portatile? È difficile sostenere che quello più grande sia il più portatile, quando quello non dimensionato può essere eseguito su qualsiasi cosa (che supporti C) che ha numeri interi sufficientemente grandi. Mentre la dimensione è limitata solo alle piattaforme che supportano numeri interi a 32 bit. Anche se quel codice non sta effettivamente usando 32 bit.
Suppongo che un vantaggio di quest'ultimo sia che, se i tipi di dimensioni non sono supportati, si ottiene un errore di compilazione difficile. Al contrario, se int
non è abbastanza grande, si ottiene un comportamento invisibile definito dall'implementazione. C ++ 11 ha ottenuto una soluzione a questo problema con static_assert
, che potrebbe impedire la compilazione su una cosa arbitraria in fase di compilazione. Come la dimensione di un int
che è abbastanza grande per un uso particolare.