Come verificare se sono definiti numeri interi a larghezza fissa


25

In C ++, gli interi a larghezza fissa sono definiti come opzionali , ma non riesco a trovare il modo consigliato per verificare se sono effettivamente definiti.

Quale sarebbe un modo portatile per verificare se sono disponibili numeri interi a larghezza fissa?


Sembra che non ci sia una macro di test di funzionalità , ma suppongo che tu possa fare#if defined(INT8_MIN)
Zereges

2
Se la libreria std non fornisce una macro di test di funzionalità per questo, è possibile verificare se la toolchain in uso ne fornisce uno o consentire di definire un proprio test. CMake, ad esempio, consente di testare determinate funzionalità del linguaggio compilando un cppfile definito e in base al fatto che la compilazione fallisca o meno sia impostata una macro che è possibile definire.
t.niese

Se preferisci autoconf a cmake, ha dei test predefiniti per loro. AC_TYPE_INT8_Tecc.
Shawn

Se qualcuno ha qualche punteggio tag nel stdint , IMO cstdint dovrebbe essere nominato come sinonimo ( stackoverflow.com/tags/stdint/synonyms ). Non penso che abbiamo bisogno di tag C e C ++ separati per questa cosa oscura; il tag principale sulla domanda è sufficiente.
Peter Cordes,

1
@PeterCordes Questa volta ha funzionato: stackoverflow.com/tags/stdint/synonies
Andrew Henle

Risposte:


16

Per determinare se viene fornito un tipo intero a larghezza fissa, è possibile verificare se è stata definita una delle macro corrispondenti [U]INT*_MAXo corrispondenti [U]INT*_MIN.

// may be necessary for your C++ implementation
#define __STDC_LIMIT_MACROS 
#include <cstdint>

#ifdef INT32_MAX
// int32_t must be available to get here
int32_t some32bitIntVariable;
#endif

Per 7.20 tipi di numeri interi<stdint.h> , paragrafo 4 della norma C11 (notare le parti in grassetto):

Per ogni tipo descritto nel presente documento che l'implementazione fornisce, <stdint.h>deve dichiarare quel typedefnome e definire le macro associate . Viceversa, per ciascun tipo descritto nel presente documento che l'implementazione non prevede, <stdint.h>non deve dichiarare tale typedefnome né definire le macro associate .

C ++ eredita l'implementazione C tramite <cstdint>. Vedi <cstdint>vs<stdint.h> per alcuni dettagli. Vedi anche Cosa significano __STDC_LIMIT_MACROSe cosa __STDC_CONSTANT_MACROSsignificano?per dettagli su __STDC_LIMIT_MACROS.

Pertanto, se int32_tè disponibile INT32_MAXe INT32_MINdeve essere #define'd. Al contrario, se int32_tnon è disponibile, INT32_MAXINT32_MINè permesso né essere #define'd.

Nota però, come affermato da @NicolBolas in un'altra risposta , potrebbe non essere necessario controllare effettivamente.


Sarà più breve controllare [U]INT*_Cinvece delle macro min e max
phuclv

1
@phuclv Tranne che non è la stessa cosa. es. INT64_Cè definito se int64_least_tè disponibile, non se int64_tè disponibile. Fare riferimento alla documentazione
Lightness Races in Orbit

19

A grandi linee ... non lo fai.

Se è necessario utilizzare i tipi interi di dimensioni fisse, ciò significa che è necessario che questi tipi siano espressamente delle dimensioni specifiche. Cioè, il tuo codice non funzionerà se non puoi ottenere numeri interi di quelle dimensioni. Quindi dovresti semplicemente usarli; se qualcuno usa il tuo codice su un compilatore privo di tali tipi, il tuo codice non verrà compilato. Va bene, perché il tuo codice non avrebbe funzionato se fosse stato compilato.

Se in realtà non hai bisogno di numeri interi di dimensioni fisse ma semplicemente li vuoi per qualche altro motivo, usa i int_least_*tipi. Se l'implementazione può darti esattamente quella dimensione, i least_*tipi avranno quella dimensione.


4
Questo non è vero. Ho scritto stth passthrough che implementano operator = / etc per piattaforme che non supportano prima uint8_t. Ma ai fini dell'efficienza e del debug non si desidera utilizzare il passthrough a meno che non sia effettivamente necessario.
TLW

@TLW: " Ho scritto passthrough di stub che implementano operator = / etc per piattaforme che non supportano prima uint8_t. " OK, ma ... perché? Quale codice stavi scrivendo che deve essere sicuro che un byte sia 8 bit (che è presumibilmente il motivo per cui stavi usando uint8_t), ma questo codice in qualche modo doveva essere eseguito su una piattaforma in cui un byte non era 8 bit (che, oltre a usare un vecchia implementazione C ++, sarebbe l'unica ragione per cui uint8_tnon sarebbe disponibile)? Cioè, al di fuori della retrocompatibilità, perché hai dovuto farlo?
Nicol Bolas il

proprietario quindi non posso dire troppo. Base di codice condivisa che doveva supportare, tra le altre cose, uno stack hardware piuttosto eccentrico. uint8_tera molto più chiaro del precedente approccio ad hoc (e spesso rotto).
TLW,

Se si dispone di un algoritmo che viene espresso in termini, ad esempio, di byte a 8 bit, un passthrough è qualcosa che è possibile scrivere una volta ed è facile da testare. Considerando che riparare ogni posto è ad-hoc e facile da ottenere sottilmente errato. O(1)contro O(n)sforzo. Stesso motivo per cui le persone usano ad es uint16_t. Stai chiedendo "perché non usare uint32_t e lanciarlo da solo?", A cui la risposta dovrebbe essere ovvia.
TLW

@TLW: " Lo stesso motivo per cui le persone utilizzano per esempio uint16_t. " Non è la mia ragione per l'utilizzo uint16_t. La mia ragione è che sto comunicando con un dispositivo / formato / etc che si aspetta di ottenere esattamente 16 bit di dati formattati come intero binario e senza segno usando l'endian per la mia macchina, e se non riesco a ottenere un tipo che sia proprio questo, quindi comunicare efficacemente con esso è molto più difficile. Il mio programma (e le API che utilizzo con esso) fondamentalmente non può funzionare su una macchina che non lo fornisce.
Nicol Bolas,
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.