Je suis en train de lire et potasser un cours de programmation.
Le prof nous parle du fait que selon la disposition de telle ou telle variable (de types et de tailles différents), la taille de la structure, et donc la mémoire allouée, change. Enfin je ne suis pas certain que ce soit une histoire de disposition. En fait, je n'ai pas bien compris que ça :
Taille de sv1 : 12 octets
Taille de sv2 : 8 octets
Il explique comme suit :
"Les problèmes d'alignement surviennent lorsque les tailles des champs ne sont pas homogènes: les champs doivent se trouver à des adresses multiples de leur taille et la structure elle même doit avoir une taille multiple du mot (32bits dans notre exemple précédant.) "
Mais je n'ai pas saisi son explication.
Quelqu'un saurait-il me l'expliquer plus simplement/longuement/clairement ?
Bonjour ! Il me semble que l'explication ressemble à la suivante (en tout cas dans le principe, peut-être pas dans les détails) :
Imagine que le mémoire libre commence à l'octet n°100 (il me semble que c'est obligatoirement un multiple de 4 pour une machine 32 bits).
2ème déclaration :
Un size-t, en 32 bits, ça pend 4 octets. Donc ça remplit la zone 100-103, et 100 est bien multiple de 4.
Ensuite il y a un short, ça prend 2 octets, donc ça rentre dans la zone 104-105 (et 104 est bien multiple de 2)
Il reste le char, 1 octet. Il reste encore 2 octets de libres, donc on peut le placer en 106.
Au total, c'est la zone 100-107 qui est prise (l'octet 107 fait partie de la structure car sa place mémoire doit être multiple de 4), soit 8 octets.
1ère déclaration :
Un char prend 1 octet, ça rentre à l'octet 100.
Un size_t fait 4 octets. On ne peut pas le placer à l'octet 101, qui n'est pas multiple de 4. Il faut le placer dans la zone 104-107. Cette fois ça colle.
Un short fait 2 octets, on peut le placer en 108-109.
10 octets sont remplis, donc c'est une zone de 12 octets (100-111) qui est utilisée (pour être multiple de 4).
C'est un peu comme si le stockage se faisait dans des groupes de 4 octets. Le size-t ne peut pas être à cheval sur deux groupes, donc on le décale pour qu'il tienne entièrement dans un groupe.
Cela vient du fonctionnement directe de ta machine. Pour fonctionner n'importe quel processeur possède des registres : des cases de mémoires juste à côtés du processeur, je vais pas détaillé car c'est asser lourd, mais le plus important à retenir c'est que le processeur fait ses calculs sur ces registres (tous les calculs !).
C'est la taille de ces registres qui font que ta structure prend plus de place (ici 32 bits pour un registre). Puisqu'on a 4 octets, la mémoire va s’organiser en multiple de 4 pour stocker les infos. On pourrait se passer de ce multiple de 4 mais il y a aussi la façon de programmer qui entre en compte : pour se déplacer en mémoire dans un programme on ne dit pas au processeur "va là-bas" mais "déplace toi de ...", on doit donc avoir une mémoire bien organisé pour pas se perdre.
Maintenant que nous avons une vue de la mémoire on peut revenir à la structure. Dans une structure de C les différentes valeurs sont mise à la suite dans la mémoire mais on ne peut pas placer une valeur sur plusieurs ligne (exception des longs mais eux sont particulier). On peut donc écrire sur les 32 bits du registre 4 char mais qu'un seul int. On va donc avoir avec tes structures:
struct 1 :
0x0020 | char | x | x | x |
0x0024 | size_t |
0x0028 | short | x | x |
... free ...
-> on perd 5 octets
struct 2 :
0x0020 | char | short | x |
0x0024 | size_t |
... free ...
-> on perd 1 octets (et gagne 4 octets sur struct1)
NB : il est assez difficile de connaitre la taille des registres sur un PC car les architectures 32 et 64 bits qualifie la largeur du bus d'adresse. Mais sur un PC 64 bits il sera très probable d'avoir des registres de 64 bits car c'est plus simple pour stocker des adresses mémoires avec lesquels le processeur joue 80% (j'en sais rien mais c'est beaucoup) de son temps.
BrigitteLPB : il me semble que même sur les vieilles machines 32 bits, les 'short' font normalement 2 octets (même si ce n'est pas une obligation). En tout cas ça ne change rien au résultat.
Très bonne idée, les dessins ! Du coup je les ajoute à la définition de la structure :
struct s_v1
{
char c1; |<char>| |
size_t i1; |<---------size_t---------->| Tout rentre dans 12 octets
unsigned short s1; |<---short--->| |
};
struct s_v2
{
size_t i1; |<---------size_t---------->|
unsigned short s1; |<---short--->|<char>| | Tout rentre dans 8 octets
char c1;
BrigitteLPB : il me semble que même sur les vieilles machines 32 bits, les 'short' font normalement 2 octets (même si ce n'est pas une obligation). En tout cas ça ne change rien au résultat.
Il est vrai ! C'est que je n'est pas l'habitude de croiser des shorts et encore moi leurs tailles xD
C'est beaucoup plus clair maintenant. Mille mercis :))
Et merci pour les schémas, c'est vraiment plus clair de se le représenter ainsi
Donc en fait la taille d'une structure n'est pas nécessairement la somme de ses parties. Bon, je ne sais pas si à l'heure actuelle ça peut avoir une importance de faire en sorte de "sauvegarder" de la mémoire en plaçant correctement les différentes variables.
C'est beaucoup plus clair maintenant. Mille mercis :))
Et merci pour les schémas, c'est vraiment plus clair de se le représenter ainsi
Donc en fait la taille d'une structure n'est pas nécessairement la somme de ses parties. Bon, je ne sais pas si à l'heure actuelle ça peut avoir une importance de faire en sorte de "sauvegarder" de la mémoire en plaçant correctement les différentes variables.
Enfin bref, merci encore !
- Edité par Batche il y a moins de 30s
Je te dirais de ne pas chercher à optimiser l'espace mémoire car en passant sur des registres de 64 bits ta struct 1 se retrouve dans le cas de la struct 2 donc pas besoin d'optimiser. ça serait plus à faire à la fin d'un développement lors de la phase d'optimisation pour une machine précise.
Il y a un moyen simple d'optimiser l'espace, c'est de placer les éléments de la structure par ordre décroissant de taille: - long double : 8, 10 ou 16 octets (alignés 16, 8 ou 4 suivant l'architecture) - long long : 8 ou 16 octets (alignés 8 ou 16) - double : 8 octets (alignés 8 ou 4), peut être de taille 4 octets sur microcontroleurs. - long : 4 ou 8 octets (alignés 2, 4 ou 8) - int : 2, 4 ou 8 (alignés 2, 4 ou 8) - float : 4 octets (alignés 2 ou 4) - short : 2 ou 4 octets (alignés 2 ou 4) - char : 1 ou 2 octets (jamais vu 4 octets), ont toujours l'alignement minimal par définition.
On voit qu'il existe juste une ambiguïté qui dépend de l'architecture processeur; faut-il mettre le int avant ou après le float. Pour les microcontrôleurs c'est plutôt float avant int, pour les processeurs récents ça serait l'inverse.
Il y a un article Wikipedia sur le pourquoi du padding (remplissage ou rembourrage) permettant l'alignement des données arrangées pour être lues et écrites en mémoire de manière plus optimisée par le processeur.
n'insérera pas d'octets de rembourrage pour aligner quoi que ce soit.
Le padding peut ne pas être souhaitable, par exemple, si tu veux lire le secteur de boot d'un disque avec une struct conçue pour récupérer les données telles qu'elles sont sur le disque et que tu veuilles pouvoir écrire cette struct sur le disque :
Dalfab, ok, c'est cool comme méthode j'y penserai la prochaine fois.
Quant à ta réponse Dlks, je n'en suis pas encore là mais je méditerai sur cette question que je ne pige pas trop encore.
Merci en tout cas.
Taille d'une structure inégale selon disposition
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
En recherche d'emploi.