3 puntos por GN⁺ 2024-10-16 | 1 comentarios | Compartir por WhatsApp
  • La edición revisada de Modern C adaptada al nuevo estándar de C está disponible para descarga gratuita, lo que permite volver a consultar y estudiar el lenguaje C con base en C23
  • El eje de la revisión es la incorporación de C23, con foco en facilitar la transición al nuevo estándar en sincronía con el proceso y los tiempos de publicación de ISO
  • Las nuevas versiones de los principales compiladores ya implementan la mayoría de las funciones de C23, por lo que los cambios del libro van más allá de una presentación experimental y se conectan con entornos de uso reales
  • Cambios del lenguaje y la biblioteca como _BitInt(N), nullptr, auto, typeof y constexpr se reflejan ampliamente, e impactan también en la forma de escribir código C existente
  • Se agregaron apéndices de transición y encabezados include temporales para poder probarlo de inmediato en plataformas existentes, aunque el MEAP de Manning todavía sigue en curso

Materiales gratuitos y documentos del estándar

  • La edición C23 de Modern C se puede descargar gratis
  • En la página dedicada del libro también se pueden encontrar materiales relacionados
  • La edición revisada ajusta varias explicaciones, pero su objetivo central es reflejar C23, el nuevo estándar de C
  • Entre los documentos de acceso público, el material más cercano al contenido del nuevo estándar es el PDF N3220
  • Las nuevas versiones de los principales compiladores ya implementan la mayor parte de las nuevas funciones que trae C23

Cambios del lenguaje en C23 y apoyo para la transición

  • Los cambios relacionados con enteros ocupan una parte importante
    • Se agrega el nuevo tipo de precisión de bits _BitInt(N)
    • Se agregan nuevos encabezados de la biblioteca C para aritmética con verificación de overflow y manipulación de bits
    • Se refleja la posibilidad de tipos de 128 bits en arquitecturas modernas
    • También incluye mejoras sustanciales en los tipos enum
  • También se incluyen otros conceptos nuevos de C23
    • La constante nullptr y su tipo base
    • Anotaciones sintácticas mediante attributes
    • Herramientas de programación genérica de tipos, incluidas auto y typeof
    • Inicialización predeterminada con {}, aplicable también a arreglos de longitud variable
    • constexpr para constantes con nombre de todos los tipos
  • El nuevo material también cubre expresiones compuestas, lambdas, “internacionalización” y un enfoque integral sobre fallas de programa
  • Se agregaron apéndices y encabezados include temporales para poder empezar con C23 de inmediato en plataformas existentes
  • El MEAP de la nueva edición de Manning todavía está abierto

1 comentarios

 
GN⁺ 2024-10-16
Opiniones de Hacker News
  • A diferencia de little-endian, que es el orden de almacenamiento de mi máquina, al esquema en el que la representación de los dígitos más significativos viene primero se le llama big-endian; pero decir que ambos se usan comúnmente en procesadores modernos me suena algo exagerado, porque casi no queda nada aparte de s390x
    Supongo que pronto llegará el comentario sobre la arquitectura big-endian de nicho/obsoleta favorita de todos

    • Arm es bi-endian y sigue vivo en la mayoría de los teléfonos
      Como en otro comentario destacado, que algo sea moderno no necesariamente significa que sea popular o ampliamente usado
    • POWER es bi-endian. Linux on POWER reciente es little-endian, y antes era común Linux on POWER en big-endian, pero las distribuciones hicieron la transición hace algunos años. En cambio, AIX e IBM i son big-endian
      AIX e IBM i quizá no estén tan activos como los mainframes de IBM, pero se puede decir que AIX está más vivo incluso que Solaris o HP/UX, y más aún si se lo compara con los muchos Unix comerciales de antes. IBM i también apenas se mantiene, pero está mucho más vivo que plataformas midrange legadas de la competencia cuyo soporte del proveedor terminó oficialmente, como HP MPE
    • MIPS todavía está bastante vivo en hardware de redes de consumo
    • En cierto sentido, también se podría decir que todos los procesadores lo usan comúnmente, porque el orden de bytes de red es big-endian
    • ¿Sparc no es big-endian?
  • El aspecto más importante de C es la portabilidad. La clave es que va desde microcontroladores pequeños hasta casi cualquier plataforma de cómputo, y me pregunto si una nueva versión de C llegará a adoptarse en esa medida
    Si quisiera usar lo más avanzado, creo que elegiría C++2x o Rust antes que C. ¿Me estoy perdiendo de algo? Me intriga qué beneficios ofrece este supuesto C moderno

    • Una de las ventajas de escribir código C es no tener que meterse en discusiones molestas sobre cómo debería verse el código idiomático o qué subconjunto del lenguaje es el correcto
      Si hablamos de lo más avanzado, recomendaría Zig. Tiene una complejidad de lenguaje mucho menor que C++ moderno y Rust. Un buen efecto secundario, menos llamativo, de C23 es que alinea mejor sintaxis como ... = {} y {0} con C++, lo que hace menos molesto para los mantenedores de bibliotecas en C dar soporte a quienes quieren compilar código C con un compilador de C++
    • Como ocurrió antes con C11, las extensiones de GNU y funciones individuales que ahora entraron en C23, terminará adoptándose. Por ejemplo, la notación binaria 0b se usa ampliamente en el mundo de los microcontroladores
      Las cadenas de herramientas para microcontroladores suelen estar construidas sobre GCC, así que obtienen las funciones gratis. Todavía hay compiladores C propietarios que siempre van atrasados, pero ya no son tan importantes como hace 20 años
    • Estas funciones terminarán llegando a la corriente principal. Algo parecido está pasando ahora con C11
      Si no apuntas a embedded o a un conjunto muy amplio de arquitecturas, no hay razón para no usar C23 desde hoy
    • El especificador thread_local ya se usa en algunas plataformas de microcontroladores, pero antes de C11 era completamente ilegal. Aun así, simplifica mucho la gestión de memoria en entornos con hilos
      ¿Hay alguna razón para tener que entrar al mundo de C++ solo por eso?
    • Si es un objetivo soportado por LLVM/GCC, ¿no obtienes automáticamente la nueva versión de C? Aunque no la tendrás en toolchains GCC viejas modificadas por proveedores para otras arquitecturas
  • Personalmente, cosas como guard, defer, auto, constexpr y nullptr hacen que C sea mucho más complejo. Uno elige C porque necesita simplicidad; si quisiera complejidad, normalmente elegiría C++ aunque no me gustara, o mejor Go, o Elixir si fuera para servidores
    _BitInt(N) también es feo, y me recuerda a _Bool, que por suerte ahora es bool. constexpr y nullptr huelen demasiado a C++. Aun así, Modern C es un libro excelente, y me ha servido mucho para C99, que es lo que pienso seguir usando

    • La pregunta de qué tiene de malo NULL se responde leyendo los documentos relacionados, gracias a una de las pocas ventajas de la estandarización ISO: https://wg21.link/p2312
      En resumen, pasar un argumento NULL a una macro type-generic puede producir resultados sorprendentes, y el estatus de expresiones condicionales como (1 ? 0 : NULL) y (1 ? 1 : NULL) depende de cómo esté definido NULL. Además, pasar NULL a una función variádica que espera un puntero puede tener consecuencias graves. En muchas arquitecturas actuales, int y void* tienen tamaños distintos, así que si NULL es simplemente 0, se pasa a la función un argumento del tamaño incorrecto
    • Creo que la complejidad no crece de forma lineal. De hecho, muchas veces una herramienta más compleja simplifica tanto el proceso como el resultado final
      Es parecido a construir una casa. Un martillo y un destornillador son muy simples, y una grúa es extremadamente compleja, pero lo que simplifica construir una casa es la grúa. Si quisieras construir una casa solo con un martillo y un destornillador, tendrías que diseñar un procedimiento enormemente complejo
      Con los lenguajes de programación pasa lo mismo. Crear contenedores genéricos en C++ es trivial, pero en C es muy difícil. Se puede imitar hasta cierto punto con void * y casts manuales, pero es engorroso, propenso a errores y vuelve el código más complejo
      Lo mismo ocurre con std::sort y qsort. Gracias al poder de las plantillas y los objetos función, la implementación es más simple y rápida. No hace falta pasar void * ni desreferenciar en tiempo de ejecución, y la comparación puede ponerse en la propia definición de la función. No hay llamada indirecta ni paso por pila, e incluso se puede inlinear la función de comparación. La complejidad del lenguaje no significa complejidad de implementación
    • auto es útil sobre todo al trabajar con macros type-generic, pero conviene no usarlo en código común. Ojalá evitemos locuras como almost always auto, que estuvo de moda un tiempo en el mundo C++
      Lamentablemente hay pequeñas diferencias entre compiladores. Si no recuerdo mal, Clang implementa auto al estilo C++ y GCC implementa auto al estilo C, así que había diferencias sutiles con punteros auto. No sé si esa diferencia ya se corrigió
      _BitInt(N) normalmente no se usa directamente, sino mediante un typedef con el ancho necesario. Por ejemplo, typedef _BitInt(2) u2;. Sintaxis feas como _B son necesarias porque las combinaciones de guion bajo seguido de mayúscula están reservadas en el estándar C, para evitar conflictos con código existente al agregar pequeñas funciones al lenguaje. El nombre _Bool se debe a la misma razón. Hasta donde sé, defer en realidad no entró en C23
  • La definición anterior ni siquiera especificaba si NULL era un puntero o un entero. Por eso, en plataformas que no seguían el requisito de Posix de ((void*)0), era una trampa bajo los pies: no era ni de tipo puntero ni del tamaño de un puntero
    Que constexpr y nullptr huelan a C++ probablemente se debe a que fueron reimportados desde C++. Aun así, se puede seguir usando NULL; por fuera, parece que fue redefinido como nullptr

    • Este código tiene un bug y en algunas arquitecturas podría crashear: execlp("echo", "echo", "Hello, world!", NULL);
      Este código no tiene ese bug: execlp("echo", "echo", "Hello, world!", nullptr);
      Esto también está bien: execlp("echo", "echo", "Hello, world!", (char *)NULL);
  • Iba a preguntar si había una buena lista de libros de C, pero terminé encontrando la respuesta por mi cuenta. Aquí clasifican Modern C como de nivel intermedio
    https://stackoverflow.com/questions/562303/the-definitive-c-...

    • Me gusta Modern C y en varios lugares lo han evaluado positivamente. Estoy de acuerdo en que es intermedio
      Como acompañantes modernos de C para K&R, creo que 21st Century C de Ben Klemens y C Programming: A Modern Approach de King son alternativas más accesibles
    • También vale la pena ver Fluent C: Principles, Practices and Patterns de Christopher Preschern
    • Esta lista no está completa. Por ejemplo, falta Effective C: https://nostarch.com/effective-c-2nd-edition
      En lo personal, prefiero Effective C antes que Modern C. Modern C es muy riguroso, al punto de sentirse como leer una especificación anotada del lenguaje, algo que puede ser necesario para expertos, pero que para alguien como yo, que usa C de forma ligera, resulta tedioso de leer
  • Algunas de las extensiones High C de Metaware me gustan bastante
    https://news.ycombinator.com/item?id=41647843
    https://news.ycombinator.com/item?id=38938402

  • Desde hace más de un año uso C++ moderno en un proyecto personal, un intérprete de lenguaje, pero por la carga mental de C++ y los problemas de herramientas sigo pensando en cambiarlo a C. IntelliSense de Visual Studio todavía casi no funciona cuando se usan módulos de C++20, y por fallas del lenguaje demasiadas cosas terminan empujadas a la interfaz, haciendo que los tiempos de compilación se vuelvan horribles
    Por otro lado, ya me acostumbré demasiado a las clases, los métodos, la programación genérica y los espacios de nombres, así que quizá ya caí en la trampa

    • Llevo mucho tiempo usando C++, y no tengo ninguna intención de renunciar a los destructores para pasarme a C
      Para ese caso, ¿has considerado C#? Visual Studio encaja mucho mejor con C#
  • En Preview de macOS, al hacer clic en los enlaces del índice de la barra lateral, no funcionan correctamente

    • Probé algunos enlaces del índice en el lector PDF zathura y funcionan bien
    • El índice actual claramente está roto
  • Hace apenas unos años que pude confiar en que todos los compiladores de C soportaran C99 en una biblioteca que mantengo: https://github.com/eyalroz/printf
    Pero, como era de esperarse, unos años después se abrió un issue pidiendo compatibilidad con C89 por culpa de alguna toolchain embebida antiquísima. Así que C23 está bueno, pero se siente como algo de lo que volveremos a hablar dentro de unos 20 años

  • ¿Alguien puede enlazar algún texto que explique, de forma práctica, por qué C está básicamente estancado en C99? Casi no veo proyectos dignos de mencionar que aprovechen funciones posteriores a C11

    • C99 todavía es nuevo. Microsoft intentó matar C negándose a implementar cualquier cosa que no existiera también en C++. MSVC implementó C99 con 16 años de retraso, y solo lo mínimo. La implementación de C11 también llegó 11 años tarde
      Como C estuvo prácticamente congelado durante décadas, parece que su base de usuarios se autoseleccionó entre gente a la que le gusta C tal como es y no le molesta soportar compiladores viejos y llenos de rarezas. Quienes perdieron la paciencia o querían un lenguaje del siglo XXI se fueron a C++/Rust/Zig, etc.
    • Microsoft básicamente obstaculizó C99 al casi no implementar funciones de C99 en el compilador de C de Visual Studio hasta alrededor de 2015. Recién en 2019 reconoció el fracaso y volvió a empezar a dar soporte a versiones más recientes de C. El frontend de C de MSVC todavía sigue quedándose atrás de Clang y GCC de forma consistente
      Alrededor de 2010, MSVC todavía era muy importante, lo cual suena raro desde una perspectiva actual, en la que parece que la mayoría de los desarrolladores se mudaron a Linux. Por otro lado, tampoco hay muchos proyectos que realmente necesiten funciones de C11. C11 también quitó las VLA de C99, aunque no fue una pérdida muy lamentable. C23 podría ser la primera versión desde C99 a la que muchas bases de código en C realmente valga la pena actualizar