Pourquoi les rembourrages sont-ils ajoutés, si char vient après int?

Par exemple, il y a une structure

struct A { char a; int i; }; 

Dans ce cas, nous avons un [1 octet] + padding [3 octets] + int [4 octets] = 8.

Faisons maintenant une petite mise à jour dans la structure ci-dessus,

 struct A { int i; char a; }; 

Dans ce cas, char vient après int et il n’est pas nécessaire d’append des octets de remplissage, cela signifie sizeof (A) = 5 octets, mais dans ce cas, j’obtiens également le résultat de 8 octets. Pourquoi ?

Ok, et qu’en est-il de ce cas

 struct s { int b; double c; char a; }; 

Selon la logique donnée ci-dessous, il y a a: size = b[4 bytes] + padding[4 bytes] + c[8] + a[1] + padding[7 bytes to align with double] = 24 , mais après exécution, je reçois 16. Comment cela est-il possible?

Dans ce cas, char vient après int et il n’est pas nécessaire d’append des octets de remplissage, cela signifie sizeof(A) = 5 octets, mais dans ce cas, j’obtiens également le résultat de 8 octets. Pourquoi ?

Vous devez d’abord comprendre pourquoi un rembourrage est nécessaire?
Wiki dit que:

L’alignement de la structure de données est la manière dont les données sont organisées et accessibles dans la mémoire de l’ordinateur. Il comporte deux problèmes distincts mais liés: l’alignement des données et le remplissage de la structure de données . Lorsqu’un ordinateur moderne lit ou écrit sur une adresse mémoire, il le fait en morceaux de la taille d’un mot (par exemple, des morceaux de 4 octets sur un système 32 bits) ou plus. L’alignement des données consiste à placer les données à un décalage de la mémoire égal à un multiple de la taille du mot, ce qui augmente les performances du système en raison de la manière dont la CPU gère la mémoire . Pour aligner les données, il peut être nécessaire d’insérer des octets sans signification entre la fin de la dernière structure de données et le début du suivant, qui correspond au remplissage de la structure de données.

Pour que la taille soit multiple de 4 (alignement de int ), le deuxième extrait sera complété avec 3 octets. Après la compilation, le second extrait sera complété pour un alignement correct

 struct A { int i; char a; char Padding[3]; // 3 bytes to make total size of the structure 8 bytes }; 

EDIT: Rappelez-vous toujours les deux règles d’or du rembourrage de la structure:

  • Le rembourrage est inséré uniquement lorsqu’un élément de structure est suivi par un élément ayant une exigence d’ alignement plus grande ou à la fin de la structure.
  • Le dernier membre est complété avec le nombre d’octets requirejs afin que la taille totale de la structure soit un multiple de l’alignement le plus grand de tout membre de la structure.

En cas de

 struct s { int b; double c; char a; }; 

l’alignement aura lieu comme

 struct s { int b; // 4 bytes. b is followed by a member with larger alignment. char Padding1[4]; // 4 bytes of padding is needed double c; // 8 bytes char d; // 1 byte. Last member of struct. char Padding2[7]; // 7 bytes to make total size of the structure 24 bytes }; 

Notez également qu’en modifiant l’ordre des membres dans une structure, il est possible de modifier la quantité de remplissage requirejse pour maintenir l’alignement. Cela peut être fait par si les membres sont sortingés par ordre décroissant d’alignement.

 struct s { double c; // 8 bytes int b; // 4 bytes char a; // 1 byte. Only last member will be padded to give structure of size 16 }; 

La raison pour laquelle le compilateur doit append un remplissage à la fin de votre structure est que la structure peut faire partie d’un tableau et que chaque élément d’un tableau doit être correctement aligné.

Il semble que votre plate-forme veuille qu’un int soit aligné sur 4 octets.

Si vous déclarez un tableau de votre struct A :

 struct A array[2]; 

Ensuite, le premier membre int de array[1] devrait également avoir un alignement de 4 octets. Ainsi, le compilateur remplit votre struct A de 8 octets pour accomplir cela, alors que s’il n’y ajoutait pas de remplissage et que sizeof(struct A) était de 5 octets, le array[1] ne serait pas correctement aligné.

(Gardez à l’esprit qu’un compilateur ne peut pas insérer de remplissage entre les éléments de tableau, le remplissage doit faire partie des éléments de tableau eux-mêmes, car sizeof array doit être identique à sizeof(struct A) * 2 dans le cas ci-dessus)

Non seulement chaque membre de la struct doit être aligné sur les données, mais la struct elle struct même doit être alignée sur la taille du plus grand membre de la struct . Ainsi, le remplissage est ajouté à la struct A telle sorte que sa taille doit être un multiple de la plus grande de la taille sizeof i et de la taille sizeof a .

Consultez la FAQ C ici

Si l’on veut avoir un tableau de structures, tous les éléments du tableau doivent avoir la même taille et le même alignement. cela impliquerait que pour les objects d’un tableau, la taille doit être un multiple de l’alignement. La seule fois où il serait utile d’avoir une structure dont la taille n’est pas un multiple d’alignement, c’est si elle n’était pas incorporée directement dans un autre tableau, mais si elle faisait plutôt partie d’une autre structure. Ce genre de situation se produit parfois, mais pas assez souvent pour mériter une attention particulière dans la conception du langage.