Propuesta para C++: un byte son exactamente 8 bits
(open-std.org)- P3477R0 es una propuesta de cambio al estándar para que el tamaño del byte en C++ no quede en manos del valor definido por la implementación
CHAR_BIT, sino que se fije en exactamente 8 bits - Las plataformas modernas ya convergieron bajo el supuesto de bytes de 8 bits, y GCC, LLVM y MSVC también tienen el valor predeterminado o las macros relacionadas en 8
- POSIX exige
CHAR_BIT == 8desde POSIX.1-2001, y la adopción de la representación de enteros en complemento a dos en C++20 y C23 también va en la misma dirección - Se considera que admitir bytes que no sean de 8 bits deja pequeñas excepciones en todo el lenguaje, las bibliotecas y el toolchain, y genera una carga de casos borde que no coincide con el uso real del C++ moderno
- Aunque existen arquitecturas excepcionales como PDP-10 o algunos DSP, el punto central del debate es si el nuevo estándar de C++ debe seguir manteniendo complejidad para esos destinos
Objetivos de cambio de P3477R0
- C++ adopta la macro
CHAR_BITde C, y actualmente este valor es un valor definido por la implementación que indica la cantidad de bits de un byte - P3477R0 propone cambiar el estándar de C++ para exigir oficialmente que un byte tenga 8 bits
- La idea de fondo es que, aunque en los inicios de la computación tenía sentido permitir flexibilidad en distintos tamaños de byte, el hardware moderno casi en su totalidad convergió sobre el supuesto de bytes de 8 bits
Estado actual de compiladores y plataformas
- Los principales compiladores ya tratan los bytes de 8 bits como la realidad predeterminada
- Entre los casos históricos de soporte en GCC,
dsp16xxse eliminó en 2004 y1750aen 2002 - En búsquedas web aparecen algunos ports externos de GCC donde
BITS_PER_UNITno es 8, pero se considera que no parecen relevantes para el C++ moderno
POSIX y la tendencia en la representación de enteros
- POSIX exige las siguientes condiciones desde POSIX.1-2001
- Un byte tiene exactamente 8 bits
CHAR_BITes8SCHAR_MAXes127,SCHAR_MINes-128,UCHAR_MAXes255
- POSIX explica que, como resultado de agregar
int8_t, exigecharde 8 bits y aritmética en complemento a dos - Desde P0907r4, C++20 solo admite almacenamiento en complemento a dos, y C23 sigue la misma dirección
- Como ejemplos actuales de sistemas operativos compatibles con POSIX se enumeran AIX, HP-UX, INTEGRITY, macOS, OpenServer, UnixWare, VxWorks y vz/OS
El costo que dejan los bytes que no son de 8 bits
- El software para bytes de 8 bits y el software para bytes que no son de 8 bits no son compatibles entre sí, y se considera que el código C/C++ orientado a bytes que no son de 8 bits es, en la práctica, más cercano a dialectos incompatibles de C y C++
- El soporte para arquitecturas con bytes que no son de 8 bits deja una complejidad pequeña pero innecesaria en muchas partes del lenguaje y las bibliotecas
- Los compiladores y toolchains deben seguir cargando con casos borde que no reflejan el uso moderno
- Los programadores nuevos pueden confundirse fácilmente por estas características exóticas de C++
- Se considera que algunos programadores experimentados terminan dedicando tiempo a una “portabilidad” para plataformas inexistentes
Arquitecturas excepcionales y compromisos
- La propuesta reconoce que todavía existen procesadores con bytes que no son de 8 bits
- La pregunta central es si esos procesadores son relevantes para el C++ moderno y si sus usuarios adoptarán nuevas versiones de C++
- Como compromiso, también se plantea exigir
CHAR_BIT % 8 == 0, pero eso solo tendría sentido si el comité decide seguir admitiendo DSP u otros procesadores dondeCHAR_BITno sea 8, pero sí un múltiplo de 8 - PDP-10 se incluye en la discusión, pero se distingue que PDP-11 usa bytes de 8 bits
- Algunos DSP tratan palabras de 24 o 32 bits como “bytes”, y ese tipo de arquitecturas tenía sentido en una época en la que los tamaños de palabra variaban y el concepto de byte no estaba estandarizado
Dirección de los cambios en la redacción del estándar
- Se busca cambiar la definición de byte en
intro.memorypara especificar que el byte, la unidad básica de almacenamiento del modelo de memoria de C++, tiene 8 bits - En
climits, se propone cambiar la redacción para dejarCHAR_BITen8 - En
cstdint, como el byte tiene 8 bits, los tipos enteros de ancho especificado comoint8_t,uint8_ty sus macros relacionadas dejarían de ser opcionales - Los tipos que usan
_N_dondeNno sea8,16,32o64seguirían siendo opcionales - Se incluye un cambio para eliminar las 4 cláusulas mandates relacionadas con
CHAR_BIT == 8dentro delocalization
Relación con el estándar C
- La propuesta examina si C++ debe seguir siendo relevante para arquitecturas con bytes que no son de 8 bits
- El comité de C podría llegar a una conclusión distinta para el lenguaje C
- Aunque lo ideal sería que ambos comités se alinearan, esta propuesta deja en manos de WG14 y del grupo de enlace SG22 informar a WG21
1 comentarios
Opiniones en Hacker News
En la serie de JF de “¿no podemos simplemente aceptar que las computadoras reales funcionan así?”, ya había una entrega sobre los enteros con signo son complemento a dos: "Signed Integers are Two’s Complement"
Aunque entonces este código clásico del kernel de Linux podría quedar obsoleto: https://github.com/torvalds/linux/blob/master/include/math-emu/double.h#L29
Durante una pasantía en 1986 escribí código C en una BBN C/70 que usaba bytes de 10 bits; fue una experiencia terrible, y que una máquina así haya existido ya era en sí un accidente cósmico en el mal sentido
Usaba palabras de 36 bits y bytes de 7 bits, y al llenar una palabra con bytes sobraban bits. Encima me tocó leer una cinta con datos binarios en formato de 8 bits, así que fue un caos total
Pero un C de 10 bits ya es otra historia
D dio un gran paso adelante al fijar lo siguiente: byte de 8 bits, short de 16 bits, int de 32 bits, long de 64 bits, aritmética en complemento a dos y punto flotante en IEEE
Eso ahorró una enorme cantidad de tiempo que antes se desperdiciaba intentando abstraer estas cosas para al final equivocarse, y millones de personas respiraron aliviadas. El conjunto de caracteres también era Unicode, no EBCDIC ni RADIX-50
u8/i8,u16/i16,u32/i32,u64/i64, y la aritmética también se elige de forma explícitaEl overflow de
+es comportamiento inválido y aborta en debug y releasesafe,+%hace wrapping en complemento a dos, y+|es aritmética saturada.@addWithOverflow()devuelve una tupla del tipo original yu1, ystd.math.add()devuelve un error si hay overflow.f16,f32,f64,f80yf128también son tipos IEEE de punto flotante con esas longitudes de bits respectivas. No importa cuántos bits tenga un byte; si fuera una máquina con bytes de 12 bits, bastaría usaru12ei12u8,i32son mucho mejores en todos los aspectosunsigned, pero sí estandarizó correctamente la cantidad de bits de los tipos básicosbyte = 8 bits,short = 16,int = 32,long = 64,float = 32 bit IEEE,double = 64 bit IEEETodavía hay gente que tiene que lidiar con DSP: https://thephd.dev/conformance-should-mean-something-fputc-and-freestanding#we-cannot-program-on--vibes-
Personalmente, por diversión estoy documentando una consola de fantasía de 12 bits aún no implementada con el gancho de “¡50% más bits por byte que la competencia!”, e incluso le puse inventos como “UTF-12”
Llevo años preguntando y no he recibido ninguna respuesta positiva; aparte de TI, casi no se ha mencionado a nadie, así que agregué información al borrador actualizado: https://isocpp.org/files/papers/D3477R1.html
CHAR_BIT=32en una versión como C++30, no me voy a poner a llorar ni a protestarMe pregunto si C++ realmente puede deprecar o simplificar algo
Es una pregunta sincera y no he seguido el tema en detalle. Tengo entendido que
rand()está roto y no se puede arreglar, pero hasta donde sabía ni siquiera estaba en camino a quedar deprecado. Esta propuesta parece una prueba de “¿se puede eliminar incluso el soporte para resolver un problema que literalmente nadie enfrenta?”C y C++ modernos dejaron eso atrás y exigen complemento a dos. Aquí la distinción de “as if” tampoco importa realmente, y lo mismo podría aplicarse a
CHAR_BIT, así que claramente hay precedentes de este tipo de cambiorandya está en camino a quedar deprecado y además existen alternativasTambién están
p2809 Trivial infinite loops are not Undefined Behavior,p1152 Deprecating volatile,p0907 Signed Integers are Two's Complement,p2723 Zero-initialize objects of automatic storage duration,p2186 Removing Garbage Collection Support. Así que sí se puede cambiarLas especificaciones de excepciones también se eliminaron, aunque hay quienes quieren revivirlas para excepciones de tipos por valor.
auto_ptrtambién se eliminó por su diseño roto. Pero desde el punto de vista de la simplificación no mejora mucho, porque igual hay que conocer la forma anteriorAlgo así como que hace falta un nuevo símbolo en C++ para señalar de forma estable bytes de 8 bits sin romper compatibilidad. Por ejemplo,
unsigned byte8,signed byte8en complemento a dos y hastabyte8con comportamiento de signo indefinido. También se podría agregarunsigned decimal byte8ysigned decimal byte8, con rango de 0~10 y -10~+10 para contadores,centimal byte8con 0~100 y -100~+100 para contadores que incluso se preocupan por el costo del byte, algún tipo más o menos suficiente para el campoagede una base de datos y, claro, tambiénfloat byte8rand()está rotoGenera valores que parecen aleatorios, y ese es el objetivo. Obviamente no produce números aleatorios criptográficamente seguros, y las funciones equivalentes en otros lenguajes tampoco. Si lo que se quiere es un entero razonablemente aleatorio que se calcule rápido,
rand()funciona suficientemente bienGracias por interesarte en la propuesta; con base en los comentarios recibidos hasta ahora preparé un borrador actualizado: https://isocpp.org/files/papers/D3477R1.html
En particular, me quedó grabada la frase “el problema no es si todavía existen arquitecturas donde un byte no son 8 bits. ¡Existen! El problema es si a ellas les importa el C++ moderno, y si al C++ moderno le importan ellas”
Tengo sentimientos encontrados con esta propuesta. Por un lado, evidentemente tiene razón y
CHAR_BITdistinto de 8 no tiene un uso significativoPor otro lado, también se siente como rendirse ante una visión justa del mundo en la que el mundo debe ser sensato y razonable solo con base en un modelo personal y excesivamente simplificado del interior de una computadora. Ese enfoque te puede llevar bastante lejos, pero al final es un callejón sin salida, y tarde o temprano hay que aceptar que no sabes nada y que, bajo la condición de que la documentación sea correcta, lo mejor a lo que puedes aspirar es a un argumento formal de que construiste un programa correcto. Es un salto intelectual grande, y personalmente cuanto más tiempo pasé sin verme obligado a reconocerlo, más difícil fue después superarlo. Aun así, como parece que los proyectos físicos con electrónica se están volviendo populares entre principiantes, ojalá el nuevo estándar pase de “lee la documentación” a “lee el maldito datasheet”
autoconfveo que revisan la cantidad de bits por byte y la guardan enconfig.h, como si alguien realmente pensara actuar en función de ese valorHaría falta alguna forma de revisar todo el código previo durante la compilación para verificar si ese macro ya se usa. Este tipo de cambio incompatible también corre el riesgo de partir el lenguaje. Tampoco está clara la dificultad de probar si una base de código existente usa el macro
CHAR_BITy si puede actualizarse a un compilador nuevo. También surgen dudas sobre qué bibliotecas se considerarían rotas, o si habría problemas al interactuar con otro código compilado usandoCHAR_BIT. Estoy de acuerdo en que resulta contraintuitivo, pero preferiría que primero existiera una herramienta de migración y que se demostrara que la transición es segura incluso en casos extremosMe gusta porque es una propuesta tremendamente picante y al mismo tiempo indiscutible
Me parece totalmente bien forzar
int8_t == char == 8 bits, pero no estoy convencido de difundir la idea equivocada de que un byte son 8 bitsUn byte de 8 bits se llama octeto. Al mismo tiempo, desde C++17
byteya es algo parecido a un “alias” dechar: https://en.cppreference.com/w/cpp/types/byteEn los 45 años posteriores nunca he visto que “byte” se use con otro significado, así que si existe una definición de “byte” que no sea de 8 bits, necesito ver la fuente
Esto no es una afirmación descriptiva sino una afirmación normativa
int8 == signed charstd::cout << (int8_t)32 << std::endl;obviamente debería imprimir 32No tiene que ver con C++, pero me gusta bastante la idea de una retro microcomputadora de bytes de 6 bits. Sería algo donde 24 bits forman una palabra
Las microcomputadoras normalmente manejan pocos objetos y prefieren arreglos sobre punteros, así que se puede ahorrar memoria. VGA usaba 6 bits por color, se puede crear un alfabeto legible con una matriz de 6x4 bits, incluso lenguajes básicos como LISP o Forth caben en un alfabeto de 6 bits, y el System/360 original solo usaba direcciones de 24 bits. Una memoria de 12 MiB con unidades direccionables independientes de 6 bits debería ser suficiente para cualquiera. Si no alcanza, se podría extender FAT-12 de forma natural a FAT-24, o usar punteros de 48 bits, tan útiles como los punteros de 64 bits