memcpy
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user