diff --git a/PROGRESO.md b/PROGRESO.md index 1ed4534..4ab337f 100644 --- a/PROGRESO.md +++ b/PROGRESO.md @@ -4,8 +4,11 @@ - **Fase 2**: buffer dinámico. La Fase 1 está cerrada en Fedora, pero falta probarla en Windows. -- Paso actual: 2.3b, `escpos_buffer_append` (varios bytes: puntero `const` + - cantidad + `memcpy`). El 2.3a ya está hecho: `buffer_reserve`, `static`, `t` en `nm`. +- Paso actual: 2.3b. `hello.c` ya usa bien `goto cleanup` (punteros a `NULL` + uno por línea, `result`, un solo `return`), sin avisos con gcc ni clang, y + Valgrind limpio. Falta `escpos_buffer_append`: el parámetro con la cantidad, + `const`, reservar `len + cantidad`, `memcpy` y el comentario de la cabecera. + Ahora copia 1 byte (`sizeof *byte`). - Entorno activo: Fedora 42 nativo (gcc 15.2, clang 20, make 4.4, gdb 17, valgrind 3.26). @@ -36,6 +39,7 @@ `$@ $< $^`, `.PHONY`. - Pila y montón, `malloc`/`free`/`realloc`, `NULL`, propiedad de punteros, tipo opaco, `typedef`, `->`, `uint8_t`/`size_t`, qué tipo usar. +- Liberar en caminos de error sin `defer`: patrón `goto cleanup`. - Depuración: *segfault* (139), `free(): invalid pointer` (134), gdb básico, y leer errores e informes de fugas en Valgrind. @@ -76,6 +80,10 @@ cambiaba (`buffer->cap`) o que empezaba en 0, y eso daba bucles infinitos. Lo resolvió siguiendo los valores vuelta a vuelta. Seguir pidiéndole trazas a mano. +- Declaraciones múltiples: escribió `escpos_buffer *a, *b, *c = NULL;` creyendo + que las tres valían `NULL` (solo la última). Lo detectó clang con + `-Wsometimes-uninitialized`. Ahora declara una variable por línea. +- Variables locales sin inicializar: creía que valían `NULL` como en Go. - Impresoras físicas: sin registrar marca y modelo. - Confunde puntero colgante ("se pierde") con fuga. Tampoco tenía claro por qué el slice viejo es seguro en Go tras `append` (el GC no libera el array viejo, diff --git a/docs/07-dynamic-memory.md b/docs/07-dynamic-memory.md index e77aab5..577c55d 100644 --- a/docs/07-dynamic-memory.md +++ b/docs/07-dynamic-memory.md @@ -387,6 +387,14 @@ cleanup: /* etiqueta: destino del goto */ } ``` +**Variables locales sin inicializar = basura.** En Go toda variable nace con +su valor cero (`nil`, `0`, `""`). En C, una variable local que no inicializas +contiene lo que hubiera antes en esa posición de la pila. Si un `goto` salta +por encima de la línea `escpos_buffer *b = escpos_buffer_new();`, esa +asignación no se ejecuta y `b` vale cualquier cosa. Pasarla a `free` es +comportamiento indefinido. (Las variables **globales** y `static` sí empiezan a +cero.) + Por qué funciona: - Todos los punteros empiezan en `NULL`, y la función de liberar acepta `NULL` diff --git a/examples/hello.c b/examples/hello.c index eed88c0..4f3099f 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -3,12 +3,15 @@ int main(void) { - + int result = 1; const char *version = escpos_version(); + escpos_buffer *buffer = NULL; + escpos_buffer *buffer_a = NULL; + escpos_buffer *buffer_b = NULL; printf("%s\n", version); - escpos_buffer *buffer = escpos_buffer_new(); + buffer = escpos_buffer_new(); if (buffer == NULL) { goto cleanup; } for (int i = 0; i < 100; i++) @@ -17,7 +20,7 @@ int main(void) if (err == -1) { goto cleanup; } } - escpos_buffer *buffer_a = escpos_buffer_new(); + buffer_a = escpos_buffer_new(); if (buffer_a == NULL) { goto cleanup; } uint8_t data[] = {0x1B, 0x40}; int err = 0; @@ -25,7 +28,7 @@ int main(void) err = escpos_buffer_append(buffer_a, data); if (err == -1) { goto cleanup; } - escpos_buffer *buffer_b = escpos_buffer_new(); + buffer_b = escpos_buffer_new(); if (buffer_b == NULL) { goto cleanup; } uint8_t data_b[300]; for (int i = 0; i < 300; i++) @@ -36,11 +39,11 @@ int main(void) err = escpos_buffer_append(buffer_b, data_b); if (err == -1) { goto cleanup; } - return 0; + result = 0; cleanup: escpos_buffer_free(buffer); escpos_buffer_free(buffer_a); escpos_buffer_free(buffer_b); - + return result; }