Como verificar se números inteiros de largura fixa estão definidos

25

Em C ++, números inteiros de largura fixa são definidos como opcionais , mas parece que não consigo encontrar a maneira recomendada de verificar se eles estão realmente definidos.

Qual seria uma maneira portátil de verificar se números inteiros de largura fixa estão disponíveis?

Rick de Water
fonte
Parece não haver macro de teste de recurso , mas suponho que você possa fazer isso#if defined(INT8_MIN)
Zereges
2
Se a biblioteca std não fornecer uma macro de teste de recurso para isso, você poderá verificar se a cadeia de ferramentas que você usa fornece uma para ela ou permite definir um próprio teste. O CMake, por exemplo, permite testar determinados recursos de idioma compilando um cpparquivo definido e dependendo se a compilação falhar ou não, uma macro que você pode definir está definida.
t.niese
Se você preferir o autoconf ao cmake, ele possui testes predefinidos para eles. AC_TYPE_INT8_Tetc.
Shawn
Se alguém tiver alguma pontuação de tag no stdint , o IMO cstdint deverá ser nomeado como sinônimo ( stackoverflow.com/tags/stdint/synônimos ). Eu não acho que precisamos de tags C e C ++ separadas para essa coisa obscura; a tag principal na pergunta é suficiente.
Peter Cordes
11
@PeterCordes Funcionou desta vez: stackoverflow.com/tags/stdint/synonym
Andrew Henle

Respostas:

16

Para determinar se um tipo inteiro de largura fixa é fornecido, é possível verificar se uma das macros correspondentes [U]INT*_MAXou [U]INT*_MINestá definida.

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

Por tipos 7.20 de número inteiro<stdint.h> , parágrafo 4 da norma C11 (observe as partes em negrito):

Para cada tipo aqui descrito que a implementação fornece, <stdint.h>deve declarar esse typedefnome e definir as macros associadas . Por outro lado, para cada tipo aqui descrito que a implementação não fornece, <stdint.h>não deve declarar esse typedefnome nem definir as macros associadas .

C ++ herda a implementação C via <cstdint>. Veja <cstdint>vs<stdint.h> para mais detalhes. Veja também O que significa __STDC_LIMIT_MACROSe o que __STDC_CONSTANT_MACROSsignifica? para detalhes sobre __STDC_LIMIT_MACROS.

Assim, se int32_testiver disponível, INT32_MAXe INT32_MINdeve ser #define'd. Por outro lado, se int32_tnão estiver disponível, também INT32_MAXnão INT32_MINserá permitido #define.

Observe, porém, como @NicolBolas afirmou em outra resposta , pode não ser necessário realmente verificar.

Andrew Henle
fonte
Será mais curto procurar por em [U]INT*_Cvez das macros min e max
phuclv
11
@ phuclv Exceto que não é a mesma coisa. por exemplo, INT64_Cé definido se int64_least_testiver disponível, não se int64_testiver disponível. Consulte a documentação
Lightness Races in Orbit
19

Em termos gerais ... você não.

Se você precisar usar os tipos inteiros de tamanho fixo, isso significa que você precisará explicitamente desses tipos para terem seus tamanhos específicos. Ou seja, seu código não funcionará se você não conseguir números inteiros desses tamanhos. Então você deve apenas usá-los; se alguém usar seu código em um compilador que não possui os tipos mencionados, seu código não será compilado. O que é bom, porque seu código não teria funcionado se fosse compilado.

Se você realmente não precisa de números inteiros de tamanho fixo, mas simplesmente os deseja por algum outro motivo, use os int_least_*tipos Se a implementação puder fornecer exatamente esse tamanho, os least_*tipos terão esse tamanho.

Nicol Bolas
fonte
4
Isso não é verdade. Eu escrevi passagens de stub que implementam operator = / etc para plataformas que não suportam uint8_t antes. Mas, para fins de eficiência e depuração, você não deseja usar a passagem, a menos que seja realmente necessário.
TLW 01/01
@TLW: " Eu escrevi passagens de stub que implementam o operador = / etc para plataformas que não suportam uint8_t antes. " OK, mas ... por quê? Qual código você estava escrevendo e que precisa ter certeza de que um byte tem 8 bits (o que é provavelmente o motivo pelo qual você estava usando uint8_t), mas esse código de alguma forma precisava ser executado em uma plataforma em que um byte não tivesse 8 bits (que, além de usar um implementação antiga de C ++, seria a única razão pela qual uint8_tnão estaria disponível)? Ou seja, fora da compatibilidade com versões anteriores, por que você precisou fazer isso?
Nicol Bolas
proprietário, então não posso dizer muito. Base de código compartilhada que precisava suportar, entre outras coisas, uma pilha de hardware bastante peculiar. uint8_tera muito mais claro do que a abordagem ad-hoc anterior (e muitas vezes quebrada).
TLW
Se você tiver um algoritmo expresso em termos de, por exemplo, bytes de 8 bits, uma passagem é algo que você pode escrever uma vez e é fácil de testar. Considerando que arrumar todos os lugares é ad-hoc e fácil de ficar sutilmente incorreto. O(1)versus O(n)esforço. Mesma razão pela qual as pessoas usam, por exemplo uint16_t. Você está perguntando "por que não usar o uint32_t e lançar você mesmo?", Para o qual a resposta deve ser óbvia.
TLW
@TLW: "A mesma razão pela qual as pessoas usam, por exemplo, uint16_t. " Essa não é a minha razão de usar uint16_t. Meu motivo é que estou me comunicando com um dispositivo / formato / etc que espera obter precisamente 16 bits de dados formatados como um número inteiro binário e sem sinal, usando o endian da minha máquina, e se não conseguir obter um tipo que seja precisamente isso, então comunicar-se efetivamente com ele é muito mais difícil. Meu programa (e as APIs que eu uso com ele) fundamentalmente não pode funcionar em uma máquina que não fornece isso.
Nicol Bolas