Si declaras Ticket_t historial[5]; y luego llamas a una función pasándole el nombre del arreglo Enviar_UART(historial);, el compilador C no envía los 5 tickets. Automáticamente convierte el nombre del arreglo en un puntero a su primer elemento (es idéntico a pasar &historial[0]). La función receptora solo recibe una dirección de memoria. Es su responsabilidad saber cómo "caminar" hacia los siguientes tickets.
La aritmética de punteros obedece a las leyes de los tipos de datos. La ecuación interna del compilador cuando haces ptr + 1 es:
$Dir_{nueva} = Dir_{actual} + (1 \times sizeof(Tipo))$
Nuestra estructura Ticket_t tiene 3 variables uint32_t (4 bytes cada una), pesando un total de 12 bytes. Si un puntero a Ticket_t está en la dirección 0x20000000 y le sumas 1 (ptr++), el puntero saltará automáticamente a 0x2000000C (C en hexadecimal es 12). ¡El compilador calcula el tamaño del salto por ti!
En C puro, es extremadamente común recorrer búferes de memoria usando un bucle while y aritmética de punteros (ptr++) en lugar de índices (array[i]). A nivel ensamblador, la aritmética de punteros suele generar código máquina ligeramente más rápido y compacto, ideal para procesadores Cortex-M.
Ejercicio 1: Navegador de Búfer para Telemetría. El módulo ESP32 nos ha pedido enviar los tickets acumulados por UART. Crearemos una función que reciba el puntero del historial y la cantidad de tickets a leer, recorriendo la memoria matemáticamente usando ptr++.
#include <stdint.h>
// Reutilizamos la estructura del Día 11
typedef struct {
uint32_t id_transaccion;
uint32_t volumen_ml;
uint32_t cobro_c;
} Ticket_t;
// Simulamos la función de bajo nivel UART
// (En la realidad, enviaría los bytes crudos a los pines TX/RX)
extern void UART_Enviar_Bytes(uint8_t *datos, uint16_t longitud);
/**
* @brief Transmite un bloque de tickets iterando con aritmética de punteros.
* @param ptr_inicio Puntero al primer ticket que queremos enviar.
* @param cantidad Número de tickets a extraer del arreglo.
*/
void Transmitir_Historial_ESP32(Ticket_t *ptr_inicio, uint8_t cantidad) {
// Validación de puntero nulo para prevenir Hard Faults
if (ptr_inicio == 0x00 || cantidad == 0) {
return;
}
// Usamos un puntero temporal de trabajo para no perder
// la referencia original si la necesitáramos.
Ticket_t *ptr_trabajo = ptr_inicio;
// Iteramos 'cantidad' de veces
while (cantidad > 0) {
// El puntero 'ptr_trabajo' actualmente apunta a un Ticket_t válido.
// Hacemos un casting a (uint8_t*) para decirle a la función UART
// que lea los datos byte por byte (12 bytes en total por ticket).
UART_Enviar_Bytes((uint8_t*)ptr_trabajo, sizeof(Ticket_t));
// LA MAGIA: Aritmética de Punteros
// Al sumar 1, el compilador avanza físicamente 12 bytes en la SRAM,
// apuntando perfectamente al inicio del siguiente ticket.
ptr_trabajo++;
// Decrementamos el contador del bucle
cantidad--;
}
}
// =====================================================================
// SIMULACIÓN DE LA LLAMADA DESDE EL HILO PRINCIPAL
// =====================================================================
extern Ticket_t historial_tickets[5]; // El array del Día 11
void Procesar_Peticion_Telemetria(void) {
// Al pasar "historial_tickets", C envía automáticamente "&historial_tickets[0]"
Transmitir_Historial_ESP32(historial_tickets, 5);
}
Hito Logrado: Lectura masiva de datos estructurados para transmisión UART.
Al procesar los tickets utilizando ptr++ en lugar de historial[i], le estás enseñando al compilador del STM32 a moverse por la memoria con una agilidad tremenda. En lugar de recalcular la base del arreglo más el índice matemático en cada vuelta del bucle, el procesador simplemente le suma 12 bytes a su registro de memoria actual y dispara la trama al ESP32. Esta es la esencia pura de la programación Bare-Metal orientada al rendimiento.
puntero + 1 siempre avanza sizeof(Tipo_Base) bytes. Es crucial que el puntero esté fuertemente tipado (ej. Ticket_t*) para que el compilador sepa cuánto medir el salto.ptr++ reduce las operaciones matemáticas de indexación requeridas por la CPU.