Files
2026-10-07 03:45:29 +02:00

6.9 KiB

Progreso

Estado actual

  • Fase 2: buffer dinámico. La Fase 1 está cerrada en Fedora y en Windows (2026-10-05).
  • 2026-10-06 (Fedora): antes del 2.3b, repaso de punteros. Le costaba qué viaja a una función, * frente a ->, la pila frente al montón y restar en hex. Se creó docs/02-pointers-visual.html (interactivo). Pendiente de que conteste: A) por qué &buffer_a - &buffer da 4; B) cuántos bytes copia su append actual con data_b.
  • 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).
  • Máquinas: sobremesa con Windows (MSYS2 UCRT64) y portátil con Fedora 42 (gcc 15.2, clang 20, make 4.4, gdb 17, valgrind 3.26). Ver "Pendiente por máquina".

Pendiente por máquina

Windows (sobremesa)

  • Hay gcc, gdb y make en C:\msys64. Faltan clang y xxd (opcionales: pacman -S mingw-w64-ucrt-x86_64-clang vim; mientras, hexdump -C).
  • Fase 1 cerrada: make, make run y Nothing to be done funcionan sin EXE gracias a la emulación de .exe de MSYS2 (ver docs/06-make.md). El ifeq ($(OS),Windows_NT) se pospone a la Fase 4, cuando haga falta -lws2_32.
  • Probar en VS Code: terminal nueva (debe abrir UCRT64), Ctrl+Shift+B y F5.
  • El 2.3b se puede avanzar aquí; la comprobación de memoria queda para Fedora.

Fedora (portátil)

  • Validar con valgrind el 2.3b cuando esté hecho (y con ASan/UBSan antes de cerrar la Fase 2).
  • Tras el git pull del 2026-10-05, comprobar que make y F5 siguen igual (se ha tocado .vscode/ y se han añadido .gitattributes y .gitignore). Los binarios de Go ya no se versionan: recompilarlos con go build si hacen falta.

Hecho

  • include/escpos.h + src/escpos.c con escpos_version(), y hello.c que la usa. Compila y enlaza a mano en Windows y en Fedora.
  • samples/hello_world.bin: ESC @, texto, LF, ESC d 5, GS V 0.
  • Emulador ESC/POS en Go (emulator/) para probar sin gastar papel.
  • Makefile con regla patrón, clean y .PHONY. Compila desde un clon limpio y sin avisos con gcc y con clang.
  • 2.1: escpos_buffer_new / escpos_buffer_free con tipo opaco. Valgrind limpio, y fuga provocada a propósito para leer el informe.
  • 2.2: escpos_buffer_append_byte con realloc: 64 bytes al principio, luego el doble. Comprobado con 100 bytes (crece de 64 a 128). Valgrind limpio. Sin el free, Valgrind da 24 definitely + 128 indirectly.
  • 2.3a: crecimiento extraído a static int buffer_reserve(buffer, min_cap): arranca en 64 o en cap y dobla hasta que cabe; un único realloc.

Conceptos de C aprendidos

  • Etapas de compilación, unidades de traducción, cabeceras, include guards, static para encapsular, nm y errores del enlazador.
  • Cadenas terminadas en '\0', const char *, 'A' frente a "A".
  • Memoria virtual de un proceso, modo usuario y modo núcleo. VmSize frente a VmRSS, overcommit y OOM killer.
  • Make: reglas, dependencias por fechas, variables, regla patrón con $@ $< $^, .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.

Forma de trabajar

  • Desde el 2026-10-02: sin vibecoding. Enunciado y pruebas, predicción antes de compilar, y pistas por niveles solo si las pide. Ante un error, primero su diagnóstico.

Decisiones de diseño

  • Prefijo escpos_ para toda la API pública.
  • escpos_buffer es un tipo opaco: declarado en escpos.h y definido en src/buffer.c. Campos uint8_t *data, size_t len y size_t cap.
  • Crecimiento del buffer: 64 bytes al principio y luego el doble.
  • Por ahora, las funciones que pueden fallar devuelven int: 0 si va bien y -1 si no hay memoria. Pendiente de cambiar a códigos de error propios.
  • Estilo: nombres en snake_case y llave de apertura en línea aparte (estilo Allman) en funciones, structs y bloques.
  • Lo generado va en build/, que se crea en las recetas con mkdir -p y no se versiona. Tampoco se versionan ejecutables ni volcados (vgcore.*).
  • Dos máquinas transparentes: .gitattributes fuerza LF en todo y marca *.bin como binario (git no toca los bytes ESC/POS). En Windows, VS Code usa la shell UCRT64 de MSYS2 para la terminal y las tareas, así que make, mkdir -p y rm -rf funcionan igual que en Fedora.

Pendiente / puntos débiles

  • Fase 1: probar el Makefile en Windows (MSYS2), con el sufijo .exe.
  • Make: le costó entender que va hacia atrás desde el objetivo y que una regla patrón es una plantilla. Repasar con docs/06-make.md.
  • Punteros: le cuesta saber cuándo hace falta * y cuándo no, y distinguir la dirección del bloque (data) de una casilla (data[i]). Le funciona la analogía de papel y casa. Reforzar con ejemplos de su propio código.
  • Tipos: usó uint8_t para un código de retorno. Repasar la tabla "Qué tipo usar" de docs/08-structs.md.
  • Valorar añadir -Wconversion a CFLAGS: detecta conversiones con pérdida que gcc no avisa por defecto.
  • Bucles: en buffer_reserve calculaba cada vuelta a partir de un valor que no 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.
  • sizeof: el 2026-10-06 dijo que sizeof buffer (un puntero) da 1 byte; da 8 en 64 bits. Y lo veía como algo que "va a la casa" mientras se ejecuta, cuando se calcula al compilar a partir del tipo.
  • Hexadecimal: no sabe restar direcciones (0xd210 - 0xd1f0). Se le enseñó a hacerlo con p en gdb y con las potencias de 16. Pide ayuda con "ni idea": darle herramientas para medir, no la cuenta hecha.
  • Se salta la predicción: el 2026-10-06 miró gdb sin predecir tres veces seguidas. Insistir en que la escriba antes de ejecutar.
  • 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, no es por la copia). Repasar con la tabla de docs/07-dynamic-memory.md.

Otros

  • goescpos/: equivalente en Go idiomático (bytes.Buffer) de lo hecho hasta ahora, para comparar.