¿Por qué todo el mundo escribe def sobre los tipos C estándar?

103

Si desea utilizar Qt , debe abrazar quint8, quint16y así sucesivamente.

Si desea utilizar GLib , debe darle la bienvenida guint8, guint16etc.

En Linux los hay u32, s16y así sucesivamente.

uC / OS define SINT32, UINT16y así sucesivamente.

Y si tiene que usar alguna combinación de esas cosas, será mejor que esté preparado para los problemas. Porque en su máquina u32se typedefterminará longy quint32se typedefterminará inty el compilador se quejará .

¿Por qué todo el mundo hace esto, si lo hay <stdint.h>? ¿Es esto algún tipo de tradición para las bibliotecas?

Amomum
fuente
8
@Mehrdad en la programación de microcontroladores puedes tener todo tipo de cosas. En AVR Mega, por ejemplo (y en consecuencia en el famoso Arduino) int es de 16 bits. Puede ser una sorpresa desagradable. En mi opinión, "corto sin firmar" requiere más esfuerzo de mecanografía. Y siempre me entristecía usar 'unsigned char' para el octeto <s> byte </s>. Carácter sin firmar, ¿de verdad?
Amomum
2
@Mehrdad El punto es que no puedes estar realmente seguro. Eso es exactamente por qué stdint.hse inventó.
glglgl
1
@glglgl: Aquí hay otra forma de ver el problema: ¿no está haciendo precisamente la pregunta incorrecta? Si está apuntando a varios sistemas, ¿por qué codificar arbitrariamente la cantidad de bits en el código en primer lugar? es decir, ¿por qué no decirlo sizeof(int) * CHAR_BIT(por ejemplo) y usarlo? Si su intes demasiado pequeño para representar su rango (por ejemplo, un índice de matriz), entonces es casi seguro que no debería usarlo de inttodos modos, sino algo como size_t. ¿Por qué tendría int32más sentido? La única vez que el ancho fijo tiene sentido es para la comunicación entre sistemas (por ejemplo, formato de archivo / red) ...
user541686
1
@Mehrdad No. A veces tengo valores (como los de un ADC o lo que sea) que necesito almacenar. Sé que tienen 16 bits de ancho. Así que la mejor ting de uso es uint16_t(o tal vez su fasto leastvariante). Mi punto es: estos tipos son convenientes de usar y tienen su razón de existencia.
glglgl
1
@Mehrdad: Sugeriría que, suponiendo que valga la pena su esfuerzo para producir código de calidad, debe definir sus propias definiciones de tipo funcionales, es decir, la forma de interactuar con mi API / el resto de mi código , y definirlas por motivos técnicos en términos de Typedefs "técnico" como size_ty / o uint64_t.
PJTraill

Respuestas:

80

stdint.hno existía cuando se estaban desarrollando estas bibliotecas. Entonces, cada biblioteca hizo sus propias typedefs.

Edward Karak
fuente
4
Y está bien, supongo que la falta de stdint.h es una buena razón, pero ¿por qué incluso hoy en día estos typedefs son más int, long y así para y no stdint? Los haría intercambiables al menos
Amomum
25
@Amomum "¿Por qué Glib (que fue desarrollado en Linux) no usó Linux typedefs?" Aunque la "base de operaciones" de glib es sin duda Linux, también es por diseño una biblioteca portátil. La definición de sus propios tipos garantiza la portabilidad: uno solo tiene que adaptar un pequeño encabezado que coincida con los tipos de biblioteca con los tipos de plataforma de destino respectivos.
Peter - Reincorpora a Monica
3
@Amomum Por qué Glib (que se desarrolló en Linux) ... No, no lo fue. Glib fue creado mucho antes que el kernel de Linux.
andy256
5
@ andy256 "GLib" no es la abreviatura de "glibc". Es una biblioteca que se derivó de gtk. No es más antiguo que Linux.
2
@ andy256: glib es 1998, linux es 1991. IOW, GLib fue creado mucho después de Linux.
MSalters
40

Para las bibliotecas más antiguas, esto es necesario porque el encabezado en cuestión ( stdint.h) no existía.

Sin embargo, todavía hay un problema: esos tipos ( uint64_ty otros) son una característica opcional en el estándar. Por lo tanto, es posible que una implementación compatible no se incluya con ellos y, por lo tanto, obligue a las bibliotecas a incluirlos hoy en día.

Ven
fuente
14
Los uintN_ttipos son opcionales, pero los tipos uint_leastN_ty uint_fastN_tno lo son.
Kusalananda
7
@Kusalananda: Lamentablemente, esos son de utilidad limitada.
Lightness Races in Orbit
16
Por supuesto, la razón de que son opcionales es que no está garantizado que no son enteros tipos con exactamente ese número de bits. C todavía admite arquitecturas con tamaños enteros bastante extraños.
celtschk
5
@LightnessRacesinOrbit: ¿Cómo son de utilidad limitada? Debo admitir que, aparte de las interfaces de hardware, no veo por qué necesitaría una cantidad exacta de bits, en lugar de solo un mínimo, para asegurarse de que todos sus valores encajen.
celtschk
23
@Amomum Los typedefs son obligatorios si la implementación tiene tipos que cumplen los requisitos: "Sin embargo, si una implementación proporciona tipos enteros con anchos de 8, 16, 32 o 64 bits, sin bits de relleno y (para los tipos firmados) que tienen una representación en complemento a dos, definirá los correspondientes nombres de typedef ". (cita de N1570, 7.20.1.1 "Tipos de enteros de ancho exacto") Entonces, si la biblioteca estándar no los tiene, una biblioteca de terceros tampoco podría hacerlo.
Eric M Schmidt
13

stdint.h se ha estandarizado desde 1999. Es más probable que muchas aplicaciones definan (efectivamente, alias) tipos para mantener una independencia parcial de la arquitectura de la máquina subyacente.

Proporcionan a los desarrolladores la confianza de que los tipos utilizados en su aplicación coinciden con los supuestos específicos de su proyecto sobre el comportamiento que puede no coincidir con el estándar de lenguaje o la implementación del compilador.

La práctica se refleja en el patrón de diseño de fachada orientada a objetos y es muy abusada por los desarrolladores que invariablemente escriben clases contenedoras para todas las bibliotecas importadas.

Cuando los cumplidores eran mucho menos estándar y las arquitecturas de las máquinas podían variar de mainframes de 16 bits, 18 bits a 36 bits de longitud de palabra, esto era mucho más importante. La práctica es mucho menos relevante ahora en un mundo que converge en sistemas integrados ARM de 32 bits. Sigue siendo una preocupación para los microcontroladores de gama baja con mapas de memoria extraños .

Pekka
fuente
1
Por supuesto, stdint.hse ha estandarizado desde 1999, pero ¿cuánto tiempo ha estado disponible en la práctica? La gente se demora en implementar y adoptar nuevos estándares, y durante ese largo período de transición, los métodos antiguos siguen siendo imprescindibles.
Siyuan Ren
1
Un inconveniente desagradable stdint.hes que incluso en plataformas en las que, por ejemplo, longy int32_ttienen el mismo tamaño y representación, no hay ningún requisito de que al lanzar un int32_t*to long*produzca un puntero que pueda acceder de manera confiable a a int32_t. No puedo creer que los autores del Estándar pensaran que era obvio que los tipos compatibles con el diseño deberían ser compatibles con los alias, pero como no se molestaron en decirlo, los autores de gcc y IIRC clang piensan que el lenguaje se mejoraría si se ignoraran los alias incluso en los casos en que sea obvio.
supercat
2
@supercat: probablemente valga la pena enviarlo como una errata al comité C ... porque es innecesariamente tonto , para decirlo suavemente
LThode
@LThode: Para que el comité de C reconozca eso como un error, sería necesario que declarara oficialmente el comportamiento de clang y gcc como obtuso. ¿Crees que eso va a pasar? Lo mejor que se podría esperar (y en mi humilde opinión, la forma lógica de proceder) sería definir formas para que los programas especifiquen "modos de aliasing". Si un programa dice especifica que puede aceptar reglas de alias muy estrictas, entonces un compilador podría usar eso para permitir optimizaciones más allá de lo que actualmente es posible. Si un programa especifica que requiere reglas que son algo más amigables para el programador que las actuales ...
supercat
... pero aún permitiría muchas optimizaciones útiles, entonces un compilador podría generar código que fuera mucho más eficiente de lo que sería posible con -fno-strict-alias, pero que aún funcionaría. Incluso si no hubiera una base de código existente, ningún conjunto único de reglas podría lograr el equilibrio óptimo de optimización y semántica para todas las aplicaciones, porque diferentes aplicaciones tienen diferentes necesidades. Agregue el código base existente y la necesidad de diferentes modos debería quedar clara.
supercat
3

Entonces tienes el poder de escribir def char a int.

Un "horror de codificación" mencionó que el encabezado de una empresa tenía un punto en el que un programador quería un valor booleano, y un char era el tipo nativo lógico para el trabajo, y así lo escribió typedef bool char. Luego, más tarde, alguien encontró que un número entero era la opción más lógica y escribió typedef bool int. El resultado, años antes de Unicode, fue virtualmente typedef char int.

Creo que hay mucha compatibilidad progresiva y progresista.

Christos Hayward
fuente