Definir l'adresse d'un tableau [OWNED] - C - Programmation
Marsh Posté le 08-01-2005 à 21:23:32
FonzieV a écrit : Hello, |
/* global.c */ |
On utilise partout 'map_data' comme un tableau
/* global.h */ |
Dans le linker de la cible réelle :
reserver 256 octets à partir de l'adresse ADRESSE_EN_DUR
Marsh Posté le 09-01-2005 à 00:25:17
"/* global.c */
#include "global.h
/* definition externe : -DEMULATION ou rien */
#ifdef EMULATION
static unsigned char map_data_[MAP_DATA_SIZE];
unsigned char *map_data = map_data_;
#else
unsigned char *map_data = (unsigned char *)ADRESSE_EN_DUR;
#endif "
I see...
Par contre, faut pas que je me plante car c'est ce tableau la clef du "game engine" (au niveau de l'optimisation, c'est super hot)...
Donc tu me confirme que, au niveaux des instructions que ça va générer en asm, que :
j=tableauclassique[i];
est aussi rapide que (avec map_data comme tu l'as défini):
j=map_data[i];
?
Merci bcp.
-------------------------------------
Sinon, g testé le "tips":
static uchar dynamic_map[64*64*4];
uchar *ref_dynamic_map=dynamic_map;
ensuite, j'ai ça (dans les autres pages ou j'utilise le tableau)
extern uchar *ref_dynamic_map[];
et quand je fait ref_dynamic_map[quelquechose]
j'obtient ça:
Error : "array subscript is not an integer"
bref, c zarb.
A+
Fonzie
Marsh Posté le 09-01-2005 à 16:55:28
Si tu déclares ton tableau avec "uchar *ref_dynamic_map" d'un coté, faut pas le déclater avec "extern uchar *ref_dynamic_map[]" de l'autre... Enlève les [].
Marsh Posté le 09-01-2005 à 23:03:15
Merci bcp, ça marche nickel.
Bon et puis pour l'histoire de l'optimisation je laisse tomber, le 68K @ 8Mhz, c de la balle !
Marsh Posté le 10-01-2005 à 10:08:54
Je te confirme que l'accès aux éléments de ton tableau est aussi rapide pour les deux manières de le déclarer :
- unsigned char tab[N];
- unsigned char *tab;
Le compilateur va, dans les deux cas effectuer les mêmes opérations lors des accès. En fait, en dehors de l'allocation de mémoire, les deux écritures sont "équivalentes", la seule chose que tu ne peux pas faire avec un tableau c'est déplacer son adresse de départ (unsigned char tab[N]; ..... tab++). Du reste, si tu lui affectes une valeur dès la déclaration, ce serait une bonne idée de déclarer ton pointeur avec "const" : unsigned char * const tab = ADRESS;
Au cas où tu en aurais besoin, voici les 2 écritures pour un tableau à 2 dimensions :
- unsigned char tab[N][10];
- unsigned char (*tab)[10]; //() pour priorité entre * et []
Marsh Posté le 10-01-2005 à 15:13:35
Ok, merci à tous.
lsdyoyo, c exactement la réponse que j'attendais quand je parlais des cycles cpus, en plus avec "const", c encore plus classe (il faut souvent ajouter ce genre d'infos quand on compile au niveau maximum d'optimisation avec GCC, cf : "volatile" ).
Pour les tableaux a 2 dims, c bon a savoir mais je préfere controller toutes les multiplications moi-même (pour pouvoir faire des << et >> à la place)... Enfin, je me comprends LOL.
Merci bcp.
++
Fonzie
Marsh Posté le 11-01-2005 à 11:46:40
Deux remarques :
- const me modifie en rien le code généré (contrairement à "volatile" ). Ca permet d'obtenir des erreurs à la compilation si le source veut modifier une variable "const".
- A moins que tu ne descendes jusqu'au niveau de l'assembleur, les compilos s'en sortent bien souvent mieux que toi pour optimiser les accès aux structures ou tableaux. Il existe, notamment sur processeur Intel, des modes d'adressages spécialisés pour les tableaux d'éléments de taille 2, 4 et 8. Je pense aussi que la majorité des compilos sont suffisamment optimisés pour employer un décalage de bits plutôt qu'une multiplication si la variable est "unsigned". Dans un source, "x * 32" est plus lisible que "x << 5".
Marsh Posté le 11-01-2005 à 11:56:53
En parlant d'optimisation, y'a pas moyen d'optimiser lorsque l'on parcourt un tableau à deux dimensions par les colonnes ?? (pour que le cache serve à qqchose)
Marsh Posté le 11-01-2005 à 13:47:10
lsdyoyo a écrit : Deux remarques : |
Ca dépend, de l'implémentation, mais 'const' peut avoir une influence importante sur la taille du code généré et l'empreinte mémoire.
Par exemple :
static int a[] = {1, 2, 3, 4}; |
génère
[format Motorola, int 32-bit]
00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 |
alors que
static const int a[] = {1, 2, 3, 4}; |
génère :
et c'est tout.
En embarqué, ça peut avoir son importance...
Marsh Posté le 11-01-2005 à 15:57:45
Emmanuel Delahaye a écrit :
génère
|
Je suis surpris. Tu es sûr qu'un compilo va générer ET une allocation fixe ET un code de recopie alors que le tableau est déclaré en "static" ?!
Pour un tableau local (auto) du style "int a[] = { 1, 2 };" ok, mais en "static"... Et comment ça se passe en global, le compilo génère N appels à N recopies de bloc avant l'appel de main() ? Hummm... c'est lourd et je ne vois pas l'intérêt.
Marsh Posté le 11-01-2005 à 17:41:36
lsdyoyo a écrit : Je suis surpris. Tu es sûr qu'un compilo va générer ET une allocation fixe ET un code de recopie alors que le tableau est déclaré en "static" ?! |
J'ai constaté ça sur plusieurs plateformes embarquées (Mentor Graphics ex-MRI, notamment).
Comme je l'ai dit, ça dépend de l'implémentation. Je préfère écrire du code qui sera optimisé au mieux.
Marsh Posté le 11-01-2005 à 21:08:55
"Je suis surpris. Tu es sûr qu'un compilo va générer ET une allocation fixe ET un code de recopie alors que le tableau est déclaré en "static" ?!"
Oui c'est logique de toute façon.
"En embarqué, ça peut avoir son importance..."
Effectivement, j'ai 64Ko de workram et 256ko de program ram.
Donc ça fait une sacré dif d'avoir un tableau de 32Ko "en double".
Btw: j'utilise "volatile" comme une sorte d'information pour le compilateur.
Je travail avec des fifo's et gcc n'aime pas trop les écritures multiples genre "for(i=0;i<300;i++){*pw=56;}", il a tendance à supprimer des bout de code pour optimiser si on ne précise pas "volatile" pour les pointeurs de la fifo.
Marsh Posté le 11-01-2005 à 22:49:11
Tu dois preciser volatile parce que tes pointeurs sont volatiles. Si ton pointeur n'est pas modifie de maniere asynchrone (par un autre thread par exemple), pas besoin de volatile.
Marsh Posté le 08-01-2005 à 19:22:40
Hello,
Bon, je sais que c cho à expliquer mais ...
Je bosse sur un jeu et je dois réaliser la chose suivante:
Sur emulateur, le tableau[] doit être placé en ram (peu importe l'adresse).
Sur console, le tableau[] doir être placé en rom (à une adresse précise).
Pour passer de l'un a l'autre, j'édite qu'une seule ligne de code (et pas toutes les fois où est utilisé le tableau).
Donc, dans tout mon programme j'utilise (truc dans le genre):
unsigned char map_data[256]; //Création d'un tableau en ram, à une adresse *inconnue*.
...
map_data[x+y*32]=z;
Mais voila, comment faire pour que map_data soit placé a une adresse bien précise??!
J'ai pensé faire:
unsigned char *map_dat;
map_dat= (uchar*) 0x01100;
...
map_data[x+y*32]=z;
Mais, celà "bouffe" des instructions cpu supplémentaires à chaque utilisation du tableau (addition de deux adresses *variables*).
Alors que dans le premier exemple, le cpu additionne une valeur fixe à une valeur *variable*...
Donc, comment faire?
Il y a t'il un moyen du style (au hasard) : "#define address map_data 0x01100" ?
PS: J'utilise GCC (comme compilateur).
En GROS GROS GROS :
Je cherche à pouvoir controller l'adresse d'un tableau (qui est normalement crée en RAM, de façon incontrollable) AVANT compilation.
Merci de vos réponses.
A+
Fonzie
Message édité par FonzieV le 10-01-2005 à 15:40:35