« Programmation C/Types avancés » : différence entre les versions

Contenu supprimé Contenu ajouté
m Formatage, ajout de code
Ligne 86 :
On pourrait penser que cette structure occupera 6 octets en mémoire, et pourtant, sur une bonne partie des compilateurs, on obtiendrait une taille plus proche des 12 octets.
 
En fait, les compilateurs insèrent quasiment toujours des octets entre les champs pour pouvoir les ''aligner'' sur des adresses qui correspondent à des mots machines. Cela est dû à une limitation de la plupart des processeurs, qui ne peuvent lire des « mots » de plus d'un octet que s'ils sont alignés sur un certain adressage (alors qu'il n'y a pas de contrainte particulière pour lire un seul octet, si le type <ttcode>char</ttcode> est défini sur 8bit).
 
En se représentant la mémoire comme un tableau continu, on peut tracer le dessin suivant:
Ligne 98 :
 
Les cases <code>a</code>, <code>b</code>, <code>c</code>, ... représentent des octets, et les ''blocs'' des sections de 32 bits. 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>: le processeur fournit des instructions permettant de lire ou d'écrire directement le bloc N + 1. Dans ce cas, les octets de <code>b</code> à <code>d</code> ne sont pas utilisés; on dit alors que ce sont des octets ''de bourrage'' (ou ''padding'' en anglais).
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 d'accéder en une seule instruction aux 4 octets <ttcode>b</ttcode> à <ttcode>e</ttcode>.
 
En fait il faut garder à l'esprit que toutes les variables suivent cette contrainte: aussi bien les variables locales aux fonctions, les champs de structures, les paramètres de fonctions, etc.
Ligne 108 :
</source>
 
La valeur renvoyée est le nombre de <ttcode>char</ttcode> (i.e. d'octets la plupart du temps), entre le début de la structure et celui du champ. Le premier argument attendu est bel et bien le ''type'' de la structure et non une variable de ce type, ni un pointeur vers une variable de ce type. Pour s'en souvenir, il suffit de savoir que beaucoup d'implémentations d'<code>offsetof</code> utilisent une arithmétique de ce genre:
 
<source lang="c">