Punteros a campos de estructuras
Esta es otra técnica orientada a mejorar el código generado por el compilador (especialmente SDCC
), cuando trabajamos con micros de 8-bits
como por el ejemplo el Z80
.
Usar punteros a campos de una estructura entra quizás en la categoría de usar variables globales, porque se trata de utilizar un método de acceso a variables en C
que mejor se traduce a ensamblador de Z80
.
El caso de uso es el descrito cuando expliqué mis listas en 8-bits:
mientras el juego no acabe: leer entrada teclado/joystick actualizar entidades dibujar entidades esperar si es necesario, para velocidad constante
Cuando recorremos la lista y llamamos por ejemplo a la función de actualizar estado para cada entidad, esa entidad tendrá acceso a sus datos usando un puntero a una estructura, que tendrá un número de campos.
Veamos cómo se acceden a esos campos con el siguiente ejemplo.
#include<stdint.h> struct st_entity { uint8_t type; uint8_t x; uint8_t y; void (*update)(); void (*draw)(); struct st_entity *n; }; struct st_entity *it; void update() { it->x += 2; it->y++; }
Como ejemplo no es muy significativo porque SDCC
no va a generar muy mal código en una función tan pequeña, pero al menos podremos ver de una forma empírica cómo se accede a los campos de la estructura.
El código generado es:
_update:: ;test2.c:17: it->x += 2; ld hl, (_it) inc hl ld a, (hl) add a, #0x02 ld (hl), a ;test2.c:18: it->y++; ld hl, (_it) inc hl inc hl inc (hl) ;;test2.c:19: } ret
El compilador carga en hl
la posición de memoria guardada en el puntero a la estructura, y luego incrementa ese registro hasta llegar a la posición de memoria en la estructura donde están los datos que necesitamos.
Ya vemos como ha cargado el puntero cada vez, y se ha desplazado al campo. En estructuras más grandes y con más código, el compilador generará código que es mucho peor (probablemente usando más registros, incluso ix
).
Una vez expuesto el problema, veamos una posible solución: usar punteros a los campos de la estructura.
En el código que llama a la función update
prepararemos esos punteros antes de hacer la llamada y, aunque seguiremos teniendo el mismo problema en ese punto, el código generado en las funciones de actualización de todas nuestras entidades será más corto y más rápido.
El código que prepara la llamada sería algo como:
// variables globales uint8_t *it_x, *it_y; // antes de llamar a update it_x = &it->x; it_y = &it->y;
De esta forma la función que actualiza el estado de esta entidad podrá acceder a los campos x
e y
directamente usando *it_x
e *it_y
(que en C
significa "opera con el valor apuntado por el puntero").
void update() { *it_x += 2; (*it_y)++; }
Aún en nuestro ejemplo tan simple se puede ver la mejora:
_update:: ;test2.c:25: *it_x += 2; ld hl, (_it_x) ld a, (hl) add a, #0x02 ld (hl), a ;test2.c:26: (*it_y)++; ld hl, (_it_y) inc (hl) ;test2.c:27: } ret
Mucho mejor porque evitamos tener incrementar hl
para llegar al campo de la estructura porque estamos accediendo a él directamente con un puntero. Además vemos que algunas operaciones simples se pueden hacer directamente sobre hl
en menos pasos (como incrementar una variable de 8-bits
).
Esta técnica es probablemente la que más rendimiento me ha permitido conseguir en muchos de mis juegos para Z80
, aparte de ayudar al compilador a conseguir código más compacto y ahorrar memoria (que muchas veces es muy escasa en estas máquinas).
La única pega quizás es la notación en C
que es un poco incómoda, pero es muy fácil acostumbrarse y los beneficios bien merecen la pena ;).
Hay 3 comentarios
Además estos ejemplos son muy básicos. En una función “real” tendrás más accesos a los campos, y es posible que las operaciones para acceder a esa posición de memoria se repitan varias veces (y ahí es donde SDCC dejará de generar código eficiente).
Con los punteros sabes que siempre va a ser lo mismo: cargar el puntero y hacer la operación directamente; y te saltas el desplazamiento desde el comienzo de la estructura.
CppCon 2016: Jason Turner “Rich Code for Tiny Computers: A Simple Commodore 64 Game in C++17”
https://www.youtube.com/watch?v=zBkNBP00wJE
poco que ver con sdcc pero me pareció interesante y quería compartirlo
por un visitante, en 2020-08-01 21:27:02 ∞
Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.
por un visitante, en 2020-07-03 11:18:39 ∞