This commit is contained in:
2026-10-02 21:03:47 +02:00
parent 9d517f3607
commit b15620838b
20 changed files with 579 additions and 60 deletions
+57
View File
@@ -139,6 +139,63 @@ entero**. Eso tiene dos problemas:
Por eso las funciones de un tipo opaco reciben siempre un **puntero**. Es lo
mismo que los métodos con receptor puntero de Go (`func (b *Buffer) Free()`).
## Un puntero no sabe cuántos elementos hay
Un slice de Go lleva dentro tres cosas: puntero, `len` y `cap`. Un puntero de
C lleva **solo la dirección del primer elemento**. No hay forma de preguntarle
cuántos hay detrás.
Por eso las funciones de C que reciben un bloque de datos piden siempre **dos
parámetros**: el puntero y la cantidad.
```c
int escpos_buffer_append(escpos_buffer *buffer, const uint8_t *bytes, size_t count);
```
En Go sería un solo parámetro: `func (b *Buffer) Append(bytes []byte)`.
Si el que llama pasa un `count` mayor que lo que hay de verdad, la función lee
fuera del bloque. El compilador no puede detectarlo. Es la fuente de los
desbordamientos de memoria más famosos.
Las cadenas son la excepción: su longitud se deduce porque acaban en `'\0'`.
Pero los datos binarios (un comando ESC/POS, una imagen) pueden contener
bytes `0x00` en medio, así que necesitan su cantidad aparte.
## `const` en parámetros puntero: una promesa
```c
const uint8_t *bytes
```
Se lee "puntero a `uint8_t` que **no voy a modificar**". Es un contrato con el
que llama: le garantizas que sus datos salen intactos. Si dentro de la función
intentas escribir `bytes[0] = 0;`, el compilador da error.
- Pasar un `uint8_t *` normal donde se pide `const uint8_t *` está permitido:
solo añades una restricción.
- Al revés da aviso: estarías quitando una promesa.
**En Go** no existe. Un slice que recibes lo puedes modificar, y el que llama no
tiene ninguna garantía.
## Arrays
```c
uint8_t init[] = { 0x1B, 0x40 }; /* ESC @ */
```
- Un array de tamaño fijo. Si no pones el tamaño entre corchetes, el
compilador lo cuenta a partir de los valores.
- `sizeof init` da el tamaño **en bytes** del array completo (aquí 2). Solo
funciona con el array en su ámbito, no con un puntero.
- Al pasar un array a una función, se convierte en un **puntero a su primer
elemento** (*decay*). La función recibe la dirección, no una copia, y pierde
el tamaño. Por eso hay que pasar `sizeof init` aparte.
**En Go** `[2]byte{0x1B, 0x40}` es un array con su longitud dentro del tipo.
Se pasa por copia, y para pasarlo sin copiar se usa un slice: `init[:]`.
## `printf` y el formato
El primer argumento de `printf` es el **formato**. Nunca pases ahí una cadena