Por qué elijo Zig sobre C para programar sistemas
Why Zig over C for Systems Programming
El autor, que considera a C su lenguaje favorito, explica por qué ya no escribe código nuevo en C. Zig mantiene la cercanía al hardware y la ausencia de recolector de basura, pero añade limpieza automática con errdefer, slices que conocen su longitud, errores que el compilador obliga a manejar y comprobaciones de desbordamiento en modo debug. También es un compilador de C. El artículo reconoce los costes: Zig aún cambia y C sigue siendo más estable y extendido.
No escribo este artículo porque crea que C es malo; ¡C es mi lenguaje de programación favorito! Lo escribo porque ya no quiero escribir código nuevo en C.
- uecker
Zig es un buen lenguaje, pero esos artículos siempre comparan lenguajes nuevos con C al estilo antiguo sin usar herramientas modernas. La mayoría de las ventajas enumeradas también las puedes tener en C si estás dispuesto a adoptar herramientas y estilo modernos: comprobación de desbordamiento con signo: sanitizers, errores que no puedes ignorar: [[nodiscard]], tipo slice que conoce su tamaño: tipos modificados variablemente o tipos span.
Defer también aparecerá en los compiladores de C pronto, pero personalmente sigo pensando que el manejo de errores con goto es más claro.
(Rust tiene una ventaja para la seguridad temporal de memoria, pero esto no se aplica a Zig).
- variadix
Me he decidido por un dialecto de C++ para programación de sistemas después de usar C durante mucho tiempo. Es en su mayoría similar a C y desactivo excepciones, RTTI, etc., pero sí uso plantillas, sobrecargas, métodos, lambdas, etc.
Tengo mi propio sistema de objetos con métodos constructores que devuelven un código de estado para que no necesites excepciones, mi propia stdlib para contenedores, E/S con búfer, redes, hashing, matemáticas, hilos, async, etc.
C++ te da todas las características para construir efectivamente tu propio lenguaje, y puedes usar herramientas de primera clase ya que C++ tiene amplio soporte. Los LLM también hacen mucho más fácil construir y probar una stdlib completa por tu cuenta.
- asveikau
Solo con el primer ejemplo:
struct user *user_new(const char *name, size_t n_groups)
{
struct user *u = malloc(sizeof *u);
if (u == NULL)
goto fail;
u->name = strdup(name);
if (u->name == NULL)
goto fail_user;
u->groups = calloc(n_groups, sizeof *u->groups);
if (u->groups == NULL)
goto fail_name;
return u;
fail_name:
free(u->name);
fail_user:
free(u);
fail:
return NULL;
}
Creo que puedes representar C mejor que esto. Me gusta enfocarme en un solo bloque de limpieza y explotar el hecho de que free(NULL) es una operación nula.
struct user *user_new(const char *name, size_t n_groups)
{
struct user *u = calloc(sizeof *u, 1);
if (u == NULL)
goto fail;
u->name = strdup(name);
if (u->name == NULL)
goto fail;
u->groups = calloc(n_groups, sizeof *u->groups);
if (u->groups == NULL)
goto fail;
return u;
fail:
if (u)
{
free(u->name);
free(u->groups);
}
free(u);
return NULL;
}
Aunque ten en cuenta que esto asume que calloc(sizeof *u, 1) inicializa los punteros a NULL; si mal no recuerdo, asumir que el patrón de bits de NULL es todo ceros está técnicamente en contra del estándar, pero todos los sistemas a los que probablemente apuntes seguirán funcionando.
Si sigues el patrón de "está bien liberar punteros NULL", también puedes reutilizar una función free: […]
- pron
Además, Zig es al menos tan expresivo como C++ (pero sin la implicitud y la complejidad general del lenguaje que hace que revisar cierto código sensible, donde necesitas ver exactamente qué operaciones se realizan, sea difícil), y soporta arenas mejor que C/C++/Rust.
- drnick1
Todos estos lenguajes nuevos son ilegibles en comparación con C. Si, como a mí, te gusta lo explícito como for (size_t i = 0; i <= n; i++) total += a[i]; todos estos lenguajes nuevos no te servirán.
- kombine
D y Nim han tenido las mismas características durante años, por cierto.
- qweqwe14
Rust se apoderará de todos estos lenguajes de nicho de todos modos. Sí, Rust es un reemplazo viable para C y C++ a largo plazo. Zig solo intenta ser un punto intermedio, lo cual hemos establecido que no funciona. Zig es particularmente irrelevante comparado con Rust en la era de los LLM.
- program
> Errores que no puedes ignorar
Para mí está bien declarar una macro con `__attribute__((warn_unused_result))` para GCC y Clang, y `[[nodiscard]]` cuando el código C se compila luego con C++ (o nada).