c - strong - para que sirve el small en html
¿Qué ABI, si existe, restringe el tamaño de[u] intmax_t? (3)
A partir de la edición de 1999, el estándar ISO C define un encabezado estándar <stdint.h>
que define, entre otras cosas, los intmax_t
y uintmax_t
. Estos designan, respectivamente, "un tipo de entero (con signo | sin signo) capaz de representar cualquier valor de cualquier tipo de entero (con signo | sin signo)".
Por ejemplo, si, como es típico, los tipos de enteros con signo y sin signo más anchos son long long int
y unsigned long long int
, ambos típicamente 64 bits, entonces intmax_t
y uintmax_t
pueden definirse en <stdint.h>
siguiente manera:
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
Existe un conjunto limitado de tipos de enteros con signo y sin signo predefinidos, que van desde caracteres con signed
, unsigned
y sin formato hasta caracteres con unsigned
long long int
y unsigned
.
C99 y C11 también permiten que las implementaciones definan tipos enteros extendidos , que son distintos de cualquiera de los tipos estándar y tienen nombres que son palabras clave definidas por la implementación.
Tanto gcc como clang, en algunos, pero no en todos los destinos, admiten los tipos __int128
y unsigned __int128
. Estos actúan como tipos enteros de 128 bits, pero no se tratan como tipos enteros extendidos , y la documentación de ambos compiladores indica que no admiten ningún tipo de enteros extendidos. Debido a que estos no son tipos de enteros como el Estándar define el término, los intmax_t
y uintmax_t
son para tipos de 64 bits, no para tipos de 128 bits.
Nada de esto viola el estándar C (no se requiere que las implementaciones tengan tipos enteros extendidos, y se les permite tener extensiones arbitrarias siempre que no rompan ningún programa estrictamente conforme). Pero me parece que tendría mucho sentido que __int128
y unsigned __int128
se traten como tipos enteros extendidos, y que intmax_t
y uintmax_t
sean de 128 bits.
La razón para no hacer esto es que cambiar el tamaño de intmax_t
y uintmax_t
sería "un cambio incompatible con ABI".
La página de estado de Clang C ++ dice, en la nota a pie de página (5):
No se requieren cambios en el compilador para una implementación como Clang que no proporciona ningún tipo de enteros extendidos.
__int128
no se trata como un tipo entero extendido, porque cambiarintmax_t
sería un cambio incompatible con ABI.
(Sí, esto trata principalmente sobre C ++, pero las reglas son las mismas que para C.)
En un informe de error de gcc , se afirma que:
sizeof(intmax_t)
se corrige mediante varias ABI de LP64 y no se puede cambiar
En ambos casos, no se da ninguna referencia para esta reclamación.
Un documento ABI x86_64 titulado "Interfaz binaria de la aplicación del sistema V, Suplemento del procesador de arquitectura AMD64, Versión borrador 0.99.6" no menciona intmax_t
o uintmax_t
, ni siquiera el encabezado <stdint.h>
. Especifica tamaños y alineaciones para los tipos de enteros predefinidos (en la Figura 3.1).
Finalmente, mi pregunta: ¿Es válida la afirmación de que los tamaños de intmax_t
y uintmax_t
restringidos por un ABI? Si es así, ¿qué ABI impone tal requisito? (Y, por cierto, ¿por qué?)
(En mi opinión, tal requisito, si existe, es imprudente. Derrota el propósito del permiso del estándar C para definir tipos de enteros extendidos, y el significado pretendido de intmax_t
y uintmax_t
. Hace que sea mucho más difícil de usar. los tipos de enteros de bits efectivamente en sistemas que los admiten, mientras que recurren a tipos más estrechos en otros sistemas.)
Actualización : En N2303, titulado "intmax t, una salida", Jens Gustedt propone ajustar las definiciones de [u]intmax_t
para permitir agregar tipos de enteros extendidos más anchos que long long
sin tener que actualizar [u]intmax_t
. Por ejemplo, intmax_t
puede ser un typedef por long long
, pero la implementación todavía podría proporcionar, por ejemplo, __int128
como un tipo entero extendido .
Referencias:
- N1256 , un borrador de la norma C99
- N1570 , un borrador de la norma C11.
- N2303 , una propuesta de Jens Gustedt.
- Sistema V AMD64 ABI
Cambiar tipos como intmax_t
y uintmax_t
también cambia el ABI de todos los programas que los usan, ya que ahora se refieren a diferentes tipos.
Supongamos que tiene un programa A que utiliza una función en la biblioteca compartida B con un parámetro uintmax_t
. Si GCC cambia la definición de uintmax_t
y A (pero no B) se vuelve a compilar, entonces uintmax_t
en A y uintmax_t
en B ahora se refieren a dos tipos diferentes, rompiendo el ABI.
Como señala el Coronel Thirty Two, un compilador que realice un cambio unilateralmente interrumpiría las llamadas entre unidades de compilación que pasan parámetros uintmax_t
o devuelven valores uintmax_t
. A pesar de que la ABI de SysV no define cómo se pasan estos tipos, en la práctica, el mantenimiento de sus definiciones es parte de la conformidad con la plataforma ABI.
Incluso si no fuera por este problema ABI, un compilador todavía no podría hacer este cambio unilateralmente, ya que requeriría cambios coincidentes con la biblioteca estándar de C de cada plataforma objetivo. Específicamente, al menos requeriría actualizaciones a la familia de funciones printf
y scanf
, imaxabs
, imaxdiv
, y strtoimax
y strtoumax
y sus variantes.
Creo que la clave para entender aquí es que el hecho de que algo no esté documentado en una especificación ABI no significa que no sea parte de una ABI. Tan pronto como un tipo se utiliza en un límite de biblioteca, sus propiedades se convierten en parte de la ABI de esa biblioteca.
Al definir (u) intmax_t en un encabezado estándar y usarlas en las funciones de la biblioteca estándar, se convierten en parte del ABI de esa biblioteca, ya sea que estén incluidas en cualquier especificación ABI formal o no.
Esto es especialmente un problema para las plataformas similares a Unix donde la biblioteca estándar de C se trata como parte de la plataforma, no como parte del compilador.
Ahora sería posible hacer esta transición. Printf usa macros para especificadores de tipo, por lo que esas macros podrían definirse de manera diferente dependiendo del tamaño de intmax_t. Las macros podrían usarse de manera similar para asignar el puñado de funciones en la biblioteca estándar a diferentes implementaciones, pero es un montón de trabajo adicional para ganancias cuestionables, por lo que no es sorprendente que gcc tomara el camino de menor resistencia para agregar la funcionalidad que necesitaban.