Cómo verificar si se definen enteros de ancho fijo

25

En C ++, los enteros de ancho fijo se definen como opcionales , pero parece que no puedo encontrar la forma recomendada de verificar si realmente están definidos.

¿Cuál sería una forma portátil de verificar si hay enteros de ancho fijo disponibles?

Rick de Water
fuente
Parece que no hay macro de prueba de características , pero supongo que puedes hacerlo#if defined(INT8_MIN)
Zereges
2
Si la biblioteca estándar no proporciona una macro de prueba de características para eso, entonces puede verificar si la cadena de herramientas que usa proporciona una o le permite definir una prueba propia. CMake, por ejemplo, le permite probar ciertas características del lenguaje compilando un cpparchivo definido y dependiendo de si la compilación falla o no, se establece una macro que puede definir.
t.niese
Si prefiere autoconf a cmake, tiene pruebas predefinidas para ellos. AC_TYPE_INT8_Tetc.
Shawn
Si alguien tiene alguna valoración de etiquetas en stdint , OMI cstdint debe ser nominado como sinónimo ( stackoverflow.com/tags/stdint/synonyms ). No creo que necesitemos etiquetas C y C ++ separadas para esta cosa oscura; la etiqueta principal en la pregunta es suficiente.
Peter Cordes
1
@PeterCordes Funcionó esta vez: stackoverflow.com/tags/stdint/synomains
Andrew Henle

Respuestas:

16

Para determinar si se proporciona un tipo entero de ancho fijo, puede verificar si se ha definido una de las macros [U]INT*_MAXo la correspondiente [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

Según 7.20 tipos enteros<stdint.h> , párrafo 4 del estándar C11 (tenga en cuenta las partes en negrita):

Para cada tipo descrito aquí que proporciona la implementación, <stdint.h>declarará ese typedefnombre y definirá las macros asociadas . Por el contrario, para cada tipo descrito aquí que la implementación no proporciona, <stdint.h>no declarará ese typedefnombre ni definirá las macros asociadas .

C ++ hereda la implementación de C a través de <cstdint>. Ver <cstdint>vs<stdint.h> para algunos detalles. También vea ¿Qué significa __STDC_LIMIT_MACROSy qué __STDC_CONSTANT_MACROSsignifica? para detalles sobre __STDC_LIMIT_MACROS.

Por lo tanto, si int32_testá disponible, INT32_MAXy INT32_MINdebe ser #define'd. Por el contrario, si int32_tno está disponible, INT32_MAXtampoco INT32_MINse les permitirá #define'd.

Sin embargo, tenga en cuenta que, como dijo @NicolBolas en otra respuesta , puede que no sea necesario verificarlo.

Andrew Henle
fuente
Será más corto verificar en [U]INT*_Clugar de las macros min y max
phuclv
1
@phuclv Excepto que no es lo mismo. por ejemplo, INT64_Cse define si int64_least_testá disponible, no si int64_testá disponible. Consulte la documentación
Carreras de ligereza en órbita el
19

En términos generales ... no lo haces.

Si necesita usar los tipos enteros de tamaño fijo, eso significa que necesita explícitamente que esos tipos sean de sus tamaños específicos. Es decir, su código no será funcional si no puede obtener enteros de esos tamaños. Entonces deberías usarlos; Si alguien usa su código en un compilador que carece de dichos tipos, entonces su código no se compilará. Lo cual está bien, porque su código no habría funcionado si se compilara.

Si en realidad no necesita enteros de tamaño fijo pero simplemente los quiere por alguna otra razón, use los int_least_*tipos. Si la implementación puede darle exactamente ese tamaño, entonces los least_*tipos tendrán ese tamaño.

Nicol Bolas
fuente
44
Esto no es verdad He escrito pasaportes de código auxiliar que implementan operator = / etc para plataformas que no admiten uint8_t antes. Pero para fines de eficiencia y depuración, no desea utilizar la transferencia a menos que sea realmente necesario.
TLW
@TLW: " He escrito pasaportes de código auxiliar que implementan operator = / etc para plataformas que no admiten uint8_t antes " . OK, pero ... ¿por qué? ¿Qué código estaba escribiendo que necesita estar seguro de que un byte es de 8 bits (que es probablemente la razón por la que estaba usando uint8_t), pero este código de alguna manera necesitaba ejecutarse en una plataforma donde un byte no es de 8 bits (que, además de usar un antigua implementación de C ++, ¿sería la única razón por la uint8_tque no estaría disponible)? Es decir, fuera de la compatibilidad con versiones anteriores, ¿por qué necesita hacer esto?
Nicol Bolas
propietario, así que no puedo decir demasiado. Base de código compartida que necesitaba soportar, entre otras cosas, una pila de hardware bastante peculiar. uint8_tfue mucho más claro que el enfoque anterior ad-hoc (y con frecuencia roto).
TLW
Si tiene un algoritmo que se expresa en términos de, por ejemplo, bytes de 8 bits, un paso a través es algo que puede escribir una vez y es fácil de probar. Mientras que arreglar cada lugar es ad-hoc y fácil de conseguir sutilmente incorrecto. O(1)versus O(n)esfuerzo. La misma razón por la que la gente usa, por ejemplo uint16_t. Estás preguntando "¿por qué no usar uint32_t y lanzarlo tú mismo?", A lo que la respuesta debería ser obvia.
TLW
@TLW: "La misma razón por la que la gente usa, por ejemplo, uint16_t " . Esa no es mi razón para usar uint16_t. Mi razón es que me estoy comunicando con un dispositivo / formato / etc. que espera obtener exactamente 16 bits de datos formateados como un entero binario sin signo usando el endian para mi máquina, y si no puedo obtener un tipo que sea precisamente eso, entonces comunicarse efectivamente con él es mucho más difícil. Mi programa (y las API que uso con él) fundamentalmente no pueden funcionar en una máquina que no proporciona eso.
Nicol Bolas