Jak sprawdzić, czy zdefiniowano liczby całkowite o stałej szerokości

25

W C ++ liczby całkowite o stałej szerokości są zdefiniowane jako opcjonalne , ale nie mogę znaleźć zalecanego sposobu sprawdzenia, czy są one faktycznie zdefiniowane.

Jaki byłby przenośny sposób sprawdzenia, czy dostępne są liczby całkowite o stałej szerokości?

Rick de Water
źródło
Wydaje się, że nie ma makra testu funkcji , ale przypuszczam, że możesz to zrobić#if defined(INT8_MIN)
Zereges
2
Jeśli biblioteka std nie udostępnia makra do testowania funkcji, możesz sprawdzić, czy używany przez niego łańcuch narzędzi udostępnia go lub pozwala zdefiniować własny test. Na przykład CMake umożliwia testowanie określonych funkcji językowych przez kompilację zdefiniowanego cpppliku i zależnie od tego, czy kompilacja się nie powiedzie, czy nie, można ustawić makro, które można zdefiniować.
t.niese
Jeśli wolisz autoconf niż cmake, ma dla nich predefiniowane testy. AC_TYPE_INT8_Titp.
Shawn
Jeśli ktoś ma jakikolwiek wynik tagu w standardzie , IMO cstdint powinno być nominowane jako synonim ( stackoverflow.com/tags/stdint/synonim ). Nie sądzę, że potrzebujemy osobnych tagów C i C ++ do tego niejasnego problemu; wystarczy główny tag w pytaniu.
Peter Cordes
1
@PeterCordes Udało się tym razem: stackoverflow.com/tags/stdint/synonim
Andrew Henle

Odpowiedzi:

16

Aby ustalić, czy rodzaj całkowitą stałej szerokości jest, można sprawdzić, czy którykolwiek z odpowiadającymi [U]INT*_MAXlub [U]INT*_MINmakr jest zdefiniowana.

// 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

Według 7.20 typów całkowitych<stdint.h> , ust. 4 normy C11 (zwróć uwagę na części pogrubione):

Dla każdego opisanego tutaj typu, który zapewnia implementacja, <stdint.h>zadeklaruj tę typedefnazwę i zdefiniuj powiązane makra . I odwrotnie, dla każdego typu opisanego tutaj, którego implementacja nie zapewnia, <stdint.h>nie deklaruje tej typedefnazwy ani nie definiuje powiązanych makr .

C ++ C dziedziczy realizację pośrednictwem <cstdint>. Zobacz <cstdint>vs,<stdint.h> aby uzyskać szczegółowe informacje. Zobacz także Co oznaczają __STDC_LIMIT_MACROSi co __STDC_CONSTANT_MACROSoznaczają? po szczegóły __STDC_LIMIT_MACROS.

Zatem jeśli int32_tjest dostępny INT32_MAXi INT32_MINmusi być #define„d. I odwrotnie, jeśli int32_tnie jest dostępne, ani INT32_MAXnie INT32_MINmogą być #define„d.

Należy jednak pamiętać, jak stwierdzono w innej odpowiedzi @NicolBolas , może nie być konieczne sprawdzenie.

Andrew Henle
źródło
Krótsze będzie sprawdzanie [U]INT*_Czamiast makr min i max
phuclv
1
@phuclv Tyle że to nie to samo. np. INT64_Cjest zdefiniowany, jeśli int64_least_tjest dostępny, a nie jeśli int64_tjest dostępny. Zobacz dokumentację
Wyścigi lekkości na orbicie
19

Mówiąc ogólnie ... nie.

Jeśli musisz użyć liczb całkowitych o stałej wielkości, oznacza to, że wyraźnie potrzebujesz, aby te typy miały określone rozmiary. Oznacza to, że kod nie będzie działał, jeśli nie będzie można uzyskać liczb całkowitych o tych rozmiarach. Więc powinieneś ich po prostu użyć; jeśli ktoś użyje twojego kodu na kompilatorze, który nie ma wymienionych typów, twój kod się nie skompiluje. Co jest w porządku, ponieważ Twój kod nie działałby, gdyby się skompilował.

Jeśli tak naprawdę nie potrzebujesz liczb całkowitych o stałej wielkości, ale po prostu chcesz ich z jakiegoś innego powodu, użyj tych int_least_*typów. Jeśli implementacja może dać dokładnie ten rozmiar, least_*typy będą miały ten rozmiar.

Nicol Bolas
źródło
4
To nie jest prawda. Napisałem kody pośredniczące, które implementują operator = / etc dla platform, które wcześniej nie obsługują uint8_t. Ale dla celów wydajności i debugowania nie chcesz używać przejścia, chyba że jest to faktycznie konieczne.
TLW
@TLW: „ Napisałem kody pośrednie, które implementują operator = / etc dla platform, które wcześniej nie obsługują uint8_t. ” OK, ale ... dlaczego? Jaki kod pisałeś, który musi być pewny, że bajt ma 8 bitów (prawdopodobnie dlatego używasz uint8_t), ale ten kod jakoś musiał działać na platformie, na której bajt nie ma 8 bitów (który oprócz używania stara implementacja C ++, czy byłby to jedyny powód, dla uint8_tktórego nie byłby dostępny)? To znaczy, poza kompatybilnością wsteczną, dlaczego musiałeś to zrobić?
Nicol Bolas,
zastrzeżone, więc nie mogę powiedzieć za dużo. Wspólna baza kodów, która musiała obsługiwać między innymi dość dziwaczny stos sprzętu. uint8_tbyło znacznie jaśniejsze niż wcześniejsze podejście ad hoc (i często łamane).
TLW
Jeśli masz algorytm wyrażony w postaci np. 8-bitowych bajtów, przejście jest czymś, co możesz napisać raz i jest łatwe do przetestowania. Podczas gdy ustalanie każdego miejsca jest doraźne i łatwo może być subtelnie niepoprawne. O(1)kontra O(n)wysiłek. Ten sam powód, dla którego ludzie używają np uint16_t. Pytasz „dlaczego nie użyć uint32_t i sam go rzucić?”, Na co odpowiedź powinna być oczywista.
TLW
@TLW: „ Ten sam powód, dla którego ludzie używają np. Uint16_t. ” To nie jest mój powód do używania uint16_t. Moim powodem jest to, że komunikuję się z urządzeniem / formatem itp., Które spodziewa się uzyskać dokładnie 16 bitów danych sformatowanych jako binarna liczba całkowita bez znaku za pomocą endianu dla mojego komputera i jeśli nie mogę uzyskać typu, który jest właśnie dlatego skuteczna komunikacja z nim jest znacznie trudniejsza. Mój program (i interfejsy API, których z nim używam) zasadniczo nie może działać na komputerze, który tego nie zapewnia.
Nicol Bolas