Files
printer-driver/docs/05-libraries-and-frameworks.md
2026-09-30 10:22:42 +02:00

4.8 KiB

Frameworks y librerías del ecosistema C/C++

Qt (C++, no C)

  • Framework multiplataforma en C++: interfaces gráficas, red, hilos, bases de datos, impresión, multimedia. Funciona en Windows, Linux, macOS, Android, iOS y sistemas embebidos.
  • Lo usan KDE, OBS Studio, Telegram Desktop, VirtualBox y muchos sistemas de coche y de punto de venta.
  • Señales y slots: un objeto emite un evento y otros lo reciben. Para implementarlo, Qt tiene un precompilador propio (moc) que genera código C++ adicional antes de compilar.
  • QML: lenguaje declarativo, parecido a JS, para las interfaces modernas.
  • Licencia: LGPLv3 o comercial (algunos módulos solo GPL o comercial). Con LGPL hay que permitir que el usuario sustituya las librerías de Qt, y por eso las aplicaciones Qt se distribuyen con sus DLL al lado.
  • Relación con este proyecto: una aplicación Qt imprime con QPrinter, que pasa por el driver del fabricante y el spooler. Para ESC/POS en crudo (cajón, corte, estado) necesitaría una librería como esta.

Por qué en C casi no hay "frameworks"

  • La librería estándar de C es mínima: no trae red, ni contenedores, ni JSON, ni HTTP. Los hilos (threads.h) llegaron en C11 y son opcionales.
  • No hay gestor de paquetes oficial ni genéricos.
  • Cultura resultante: librerías pequeñas que se combinan. Muchas son de "una sola cabecera" o de un solo .c, para poder copiarlas en el proyecto sin más.

En Go: la librería estándar ya trae net/http, encoding/json, sync, etc., más go get.

Librerías C relevantes

Librería Qué es Relación
GTK + GLib/GObject Interfaz gráfica de GNOME y GIMP. GObject implementa orientación a objetos a mano sobre C Ejemplo de cómo simular clases e interfaces en C
SDL Ventanas, gráficos, audio y entrada; multiplataforma, incluido Android Juegos y multimedia
LVGL Interfaces gráficas para microcontroladores con pantalla Terminales de punto de venta embebidos
libuv Bucle de eventos multiplataforma Es el motor de Node.js: lo que hay debajo de JS
libcurl Cliente HTTP y muchos protocolos más
SQLite Base de datos completa en un solo .c Código C de referencia, muy bien probado
libusb Acceso a USB desde modo usuario Candidata para las fases 5 y 9
zlib, OpenSSL Compresión y criptografía
Unity, cmocka Frameworks de tests para C Para probar la librería
stb Colección de librerías de una sola cabecera (por ejemplo, stb_image para cargar PNG o JPEG) Posible ayuda en la fase 7 (imágenes)

Interfaces en C

Una interface de Go se implementa en C como un struct de punteros a función. Así funcionan GObject, los drivers de Linux y, en la fase 4, la abstracción de transportes de la librería (LAN, USB) detrás de una misma API.

Piezas

  • Puntero a función: las funciones también están en memoria (en la sección .text; la dirección que muestra nm junto a cada T). Un puntero a función guarda esa dirección y permite llamarla. Sintaxis: double (*area)(const void *self);.
  • void *: un puntero "a cualquier cosa", sin tipo. Hace el papel del receptor del método. C no tiene métodos: el objeto se pasa explícitamente. Go hace lo mismo por dentro: c.Area() se compila como Area(c).
  • vtable: un struct con los punteros a función de un tipo concreto. Se define una vez por tipo y la comparten todas sus instancias.
  • Valor de la "interfaz": dos punteros, {vtable, datos}.

Cómo es una interfaz de Go por dentro

En el runtime de Go, una interfaz con métodos es exactamente eso:

type iface struct {
    tab  *itab          // tipo concreto + punteros a sus métodos
    data unsafe.Pointer // el valor concreto
}

Por eso una interfaz ocupa 16 bytes en 64 bits. Y por eso existe la trampa del nil:

var p *MyError = nil
var err error = p
err != nil   // true: tab apunta al tipo *MyError, aunque data sea nil

Una interfaz solo es nil si los dos campos son nil.

Qué hace Go por ti y qué haces tú en C

Go C
Comprueba en compilación que el tipo implementa la interfaz Nadie lo comprueba: rellenas la vtable a mano
Construye el itab automáticamente Declaras la vtable como static const
El receptor tiene su tipo void *: si pasas el objeto equivocado, comportamiento indefinido
Un método que falta no compila Un puntero a NULL en la vtable provoca un fallo al llamarlo

Ejemplo real: los drivers de Linux

Cada driver rellena un struct file_operations con punteros a sus funciones open, read, write... Cuando un programa hace write() sobre /dev/usb/lp0, el núcleo llama a usblp_write a través de ese puntero. Es el io.Writer del núcleo de Linux.