« Programmation C/Types avancés » : différence entre les versions
Contenu supprimé Contenu ajouté
→Initialisation : reformulation + précision sur bog possible |
→Alignement et bourrage (padding) : reformulation et précisions |
||
Ligne 76 :
Il s'agit d'un concept relativement avancé, mais qu'il est bien de connaitre pour agir en connaissance de cause. Lorsqu'on déclare une structure, on pourrait naïvement croire que les champs se suivent les uns à la suite des autres en mémoire. Or, il arrive souvent qu'une partie de la mémoire ne soit pas utilisée.
Considérez qu'on travaille sur un environnement
<source lang="c">
Ligne 88 :
On pourrait penser que cette structure occupera 6 octets en mémoire, et pourtant, sur la majeure partie des compilateurs, pour ne pas dire tous, on obtiendrait une taille de 12 octets.
En fait, les compilateurs insèrent quasi toujours des octets entre les champs pour pouvoir les ''aligner'' sur des adresses qui correspondent à des mots machines.
En se représentant la mémoire comme un tableau continu (et avec les mêmes hypothèses que précédemment), on peut tracer le dessin suivant:
Ce comportement est en fait, non seulement dépendant de l'architecture, mais aussi du compilateur. Ce dernier possède en général des options qui permettent de paramétrer avec quelle finesse se fera l'alignement. Ces options sont bien évidemment spécifiques et pas du tout portables.▼
<pre>
Ligne 101 ⟶ 99 :
</pre>
Les cases <code>a</code>, <code>b</code>, <code>c</code>, ... représentent des octets, et les ''blocs'' des sections de 32 bits, qui seules peuvent être adressées directement par la machine. Si on suppose qu'une variable de type <code>ma_structure</code> doive être placée en mémoire à partir du bloc numéro N, alors un compilateur pourra, pour des raisons de performance, placer <code>champ1</code> en <code>a</code>, <code>champ2</code> de <code>e</code> à <code>h</code>, et <code>champ3</code> en <code>i</code>. Cela permettrait en effet d'accéder simplement à <code>champ2</code>:
Un autre compilateur (ou le même, appelé avec des options différentes) peut aussi placer <code>champ2</code> de <code>b</code> à <code>e</code>, et <code>champ3</code> en <code>f</code>, pour optimiser l'utilisation mémoire. Mais alors il devra générer un code plus complexe lors des accès à <code>champ2</code>, le matériel ne lui permettant pas
* extraire 3 octets de la valeur de champ2;
* concaténer à ces 3 octets la valeur de <tt>champ1<tt>;
* écrire la valeur résultante dans le bloc N;
* extraire le dernier octet de la valeur de champ2;
* l'écrire dans le bloc N + 1.
Un tel traitement est beaucoup plus lent qu'une écriture simple dans le bloc N + 1, c'est pourquoi le choix par défaut des compilateurs est d'insérer des octets de bourrage, en sacrifiant un perte de mémoire légère pour gagner en simplicité et en vitesse.
Toutes les variables suivent cette contrainte: aussi bien les variables locales aux fonctions, les champs de structures, les paramètres de fonctions, etc.
▲
Même si
<source lang="c">
|