Punteros en C dibujados con las direcciones reales que sacaste con gdb de build/hello. En cada pantalla, primero predices y luego miras.
malloc/realloc
El momento: el punto de parada en la línea 42 de hello.c. buffer tiene 100 bytes 'A' y buffer_a tiene un 0x1B. Contesta las preguntas y el mapa se irá rellenando.
Las cajas con ? aparecen cuando contestes.
b := &Buffer{} también puede dejar el papel en la pila y la casa en el montón. La diferencia es que lo decide el compilador (escape analysis) y tú no lo ves. En C lo decides tú: si lo pides con malloc, va al montón.
Elige una expresión, predice qué te da y cuánto ocupa, y comprueba. El dibujo marca el resultado. Regla: *, -> y [] van a la casa (un salto cada uno), y & deshace un salto.
Go esconde casi todos los saltos: b.len desreferencia solo aunque b sea un *Buffer, y s[1] no deja ver que hay un puntero dentro del slice. En C cada salto se escribe: ->, * o [].
p + i no va a ningún sitio: calcula otra dirección, i elementos más allá. p[i] calcula esa dirección y va a ella. Cuánto es un elemento depende del tipo del puntero.
1B 40 ESC @ · 48 6F 6C 61 "Hola" · 0A LF · 1B 64 05 ESC d 5 · 1D 56 00 GS V 0 · 00 libres
pNo hay aritmética de punteros (salvo con unsafe). s[i] comprueba el límite y hace panic si te pasas. En C, p[i] fuera del bloque compila sin avisar y es comportamiento indefinido: lees o escribes lo que haya al lado.
Paso a paso: escpos_buffer_append(buffer_b, data_b), con uint8_t data_b[300] declarado en main. Direcciones de ejemplo.
append(escpos_buffer *buffer, uint8_t byte[])Viajan 16 bytes. La longitud no viaja: si la función la necesita, tiene que llegarle como otro argumento.
Append(b *Buffer, data []byte)Viajan 32 bytes. El slice es una cabecera de tres campos que se copia entera, y por eso len(data) da 300 dentro de la función.
Base 16: los dígitos van de 0 a f (a=10 … f=15), y cada posición vale 16 veces la de su derecha.
| Hex | Decimal | Dónde lo has visto |
|---|---|---|
| 0x08 | 8 | sizeof de un puntero o de size_t |
| 0x10 | 16 | de data a cap dentro del struct |
| 0x18 | 24 | sizeof *buffer |
| 0x20 | 32 | de &buffer a &buffer_a; del struct a su data |
| 0x40 | 64 | cap inicial del buffer |
| 0x80 | 128 | cap tras el primer crecimiento |
| 0x100 | 256 | 16 × 16 |
Los literales son iguales: 0x20 == 32, y fmt.Printf("%x", 32) imprime 20. En C, printf("%zx", n) para un size_t y %p para un puntero.