Pourquoi l'opérateur 'sizeof' renvoie-t-il une taille plus grande pour une structure que la taille totale des membres de la structure?
Réponses
Trop de publicités?C'est en raison de l'alignement de structure. L'alignement de Structure se réfère à la capacité de le compilateur insérer la mémoire inutilisée, en une structure de sorte que les données membres sont alignées de façon optimale pour une meilleure performance. De nombreux processeurs de meilleurs résultats lorsque fondamentaux types de données sont stockées sur des octets des adresses qui sont des multiples de leurs tailles.
Voici un exemple d'utilisation typique des paramètres pour un processeur x86:
struct X
{
short s; /* 2 bytes */
/* 2 padding bytes */
int i; /* 4 bytes */
char c; /* 1 byte */
/* 3 padding bytes */
};
struct Y
{
int i; /* 4 bytes */
char c; /* 1 byte */
/* 1 padding byte */
short s; /* 2 bytes */
};
struct Z
{
int i; /* 4 bytes */
short s; /* 2 bytes */
char c; /* 1 byte */
/* 1 padding byte */
};
const int sizeX = sizeof(X); /* = 12 */
const int sizeY = sizeof(Y); /* = 8 */
const int sizeZ = sizeof(Z); /* = 8 */
On peut réduire la taille des structures, en mettant le plus grand des types de données au début de la structure et de la plus petite des types de données à la fin de la structure (structure en Z
dans l'exemple ci-dessus).
REMARQUE IMPORTANTE: le C et C++ normes de l'état que l'alignement de structure est définie par l'implémentation. Par conséquent, chaque compilateur peut choisir d'aligner les données différemment, résultant dans différents et incompatibles des présentations de données. Pour cette raison, lorsque vous traitez avec les bibliothèques qui seront utilisés par les différents compilateurs, il est important de comprendre comment les compilateurs d'harmoniser les données. Certains compilateurs ont de la ligne de commande paramètres et/ou spéciaux, #pragma
des déclarations de changement de la structure des paramètres d'alignement.
Si vous voulez la structure pour avoir une certaine taille avec GCC, par exemple, utiliser __attribute__((packed))
.
Sur Windows, vous pouvez définir l'alignement sur un octet lors de l'utilisation de la cl.exe compier avec le /Zp option.
Habituellement, il est plus facile pour le CPU d'accéder à des données qui est un multiple de 4 (ou 8), en fonction de la plate-forme et aussi sur le compilateur.
C'est donc une question de l'alignement de coeur.
Vous devez avoir de bonnes raisons de le changer.
Cela peut être dû à l'alignement d'octets et de rembourrage de telle manière que la structure sort pour un même nombre d'octets (ou des mots) sur votre plate-forme. Par exemple en C sur Linux, les 3 structures:
#include "stdio.h"
struct oneInt {
int x;
};
struct twoInts {
int x;
int y;
};
struct someBits {
int x:2;
int y:6;
};
int main (int argc, char** argv) {
printf("oneInt=%zu\n",sizeof(struct oneInt));
printf("twoInts=%zu\n",sizeof(struct twoInts));
printf("someBits=%zu\n",sizeof(struct someBits));
return 0;
}
Les membres de la taille (en octets) de 4 octets (32 bits), 8 octets (2x 32 bits) et 1 octet (2+6 bits), respectivement. Le programme ci-dessus (sur Linux avec gcc) imprime les tailles 4, 8, et 4 - où la dernière structure est matelassée pour qu'il est un seul mot (4 x 8 bits des octets sur ma plate-forme 32 bits).
oneInt=4
twoInts=8
someBits=4
Predict the output of following program.
#include <stdio.h>
// Alignment requirements
// (typical 32 bit machine)
// char 1 byte
// short int 2 bytes
// int 4 bytes
// double 8 bytes
// structure A
typedef struct structa_tag
{
char c;
short int s;
} structa_t;
// structure B
typedef struct structb_tag
{
short int s;
char c;
int i;
} structb_t;
// structure C
typedef struct structc_tag
{
char c;
double d;
int s;
} structc_t;
// structure D
typedef struct structd_tag
{
double d;
int s;
char c;
} structd_t;
int main()
{
printf("sizeof(structa_t) = %d\n", sizeof(structa_t));
printf("sizeof(structb_t) = %d\n", sizeof(structb_t));
printf("sizeof(structc_t) = %d\n", sizeof(structc_t));
printf("sizeof(structd_t) = %d\n", sizeof(structd_t));
return 0;
}
L'Alignement Des Données:
Chaque type de données en C/C++ aura alignement exigence (enfait il est mandaté par le processeur de l'architecture, non pas par la langue). Un processeur de traitement longueur de mot en tant que de données de la taille d'un bus. Sur un ordinateur 32 bits, le traitement de parole sera d'une taille de 4 octets.
Historiquement, la mémoire est l'octet adressable et organisé de façon séquentielle. Si la mémoire est organisé comme seule banque d'un octet largeur, le processeur doit exécuter de mémoire 4 cycles de lecture pour récupérer un entier. Il est plus économique de lire tous les 4 octets entier dans un mémoire de cycle. Pour prendre un tel avantage, la mémoire sera organisé en groupe de 4 banques comme le montre la figure ci-dessus.
L'adressage de mémoire toujours séquentiels. Si la banque 0 occupe une adresse X, la banque 1 banque 2 banque et 3 seront au (X + 1) (X + 2) et (X + 3) adresses. Si un nombre entier de 4 octets est alloué sur X adresse (X est multiple de 4), le processeur a besoin seulement d'un mémoire de cycle de lire toute entière.
De données d'une variable d'alignement traite de la façon dont les données stockées dans ces banques. Par exemple, l'alignement naturel de l'int sur 32 bits de la machine est de 4 octets. Lorsqu'un type de données est naturellement aligné, le PROCESSEUR récupère en un minimum de cycles de lecture.
De même, l'alignement naturel de short int est de 2 octets. Cela signifie, un short int peuvent être stockées dans la banque de données 0 – banque 1 paire ou banque 2 banque 3 paire. Un double nécessite 8 octets, et occupe deux lignes dans les banques de mémoire. Tout défaut d'alignement de la double force de plus de deux cycles de lecture pour récupérer des données en double.
Notez qu'une variable de type double sera attribué le 8 frontière d'octet sur ordinateur 32 bits et nécessite deux la mémoire de cycles de lecture. Sur un ordinateur 64 bits, basé sur le nombre de banques, variable double sera attribué le 8 limite d'octets et ne nécessite qu'un seul cycle de lecture de la mémoire.
Structure Padding:
En C/C++ un structures sont utilisées comme données de pack. Il ne fournit pas toute l'encapsulation de données ou de données des paramètres de masquage (C++ de cas est une exception en raison de sa ressemblance sémantique avec des classes).
Sortie de Programme ci-Dessus:
Pour des raisons de commodité, supposons que chaque type de structure variable est allouée sur 4 octets limite (disons 0×0000), c'est à dire l'adresse de base de la structure est multiple de 4 (besoin pas toujours nécessaire, voir l'explication de structc_t).
la structure d'Un
Le structa_t premier élément est de type char, qui est un octet alignés, suivie par short int. short int est de 2 octets aligné. Si le short int élément est octroyée immédiatement après le char de l'élément, il va commencer à un étrange adresse de la frontière. Le compilateur insère un rembourrage octet après que le char à assurer short int auront une adresse multiple de 2 (soit 2 octets aligné). La taille totale de structa_t sera sizeof(char) + 1 (rembourrage) + sizeof(short) 1 + 1 + 2 = 4 octets.
structure B
Le premier membre de structb_t est short int suivie par char. Depuis char peut être sur n'importe quel octet de limite pas de rembourrage nécessaire entre short int et char, sur l'ensemble, elles occupent 3 octets. Le prochain membre est de type int. Si l'int est attribué immédiatement, il va commencer à une étrange frontière d'octet. Nous avons besoin de 1 octet de remplissage après le char membres de l'adresse de la prochaine int membre est de 4 octets aligné. Sur le total, le structb_t exige 2 + 1 + 1 (rembourrage) + 4 = 8 octets.
structure C – Every structure will also have alignment requirements
L'application d'une même analyse, structc_t besoins sizeof(char) + 7 octets de padding + sizeof(double) + sizeof(int) = 1 + 7 + 8 + 4 = 20 octets. Cependant, la sizeof(structc_t) sera de 24 octets. C'est parce que, avec les membres de structure type de structure variables auront également l'alignement naturel. Laissez-nous comprendre par un exemple. Dire, nous avons déclaré un tableau de structc_t comme indiqué ci-dessous
structc_t structc_array[3];
Supposons, l'adresse de base de structc_array est 0×0000 pour faciliter les calculs. Si le structc_t occupe 20 (0×14) octets que nous avons calculé, le deuxième structc_t élément de tableau (indexés de 1 à 0×0000 + 0×0014 = 0×0014. C'est l'adresse de début d'indice 1 élément du tableau. Le double membre de cette structc_t sera alloué sur 0×0014 + 0×1 + 0×7 = 0x001C (décimal 28), qui n'est pas un multiple de 8 et est en conflit avec les exigences alignement du double. Comme nous l'avons mentionné en haut, l'alignement de l'exigence de la double est de 8 octets.
Afin de éviter de telles désalignement, le compilateur va introduire l'alignement exigence de chaque structure. Il sera aussi celle de la plus grande membre de la structure. Dans notre cas, l'alignement de structa_t est de 2, structb_t est 4 et structc_t est 8. Si nous avons besoin de structures imbriquées, la taille de la plus grande structure interne sera de l'alignement de l'immédiat structure plus grande.
Dans structc_t du programme ci-dessus, il y aura un rembourrage de 4 octets après int membres de la taille de la structure multiple de son alignement. Ainsi, la sizeof (structc_t) est de 24 octets. Il assure le bon alignement, même dans des tableaux. Vous pouvez vérifier.
structure D - How to Reduce Padding?
Maintenant, il peut être clair que le rembourrage est inévitable. Il y a un moyen de minimiser le rembourrage. Le programmeur doit déclarer les membres de structure dans leurs croissant/décroissant de taille. Un exemple est structd_t donné dans notre code, dont la taille est de 16 octets au lieu de 24 octets de structc_t.
En raison de l'alignement des exigences de divers types de données, chaque membre de la structure doivent être alignés naturellement. Les membres de la structure attribués séquentiellement ordre croissant. Laissez-nous analyser chaque structure déclarée dans le programme ci-dessus.
Où que, si l'entier est affecté à une adresse multiple de 4, il s'étend sur deux lignes de banques comme le montre la figure ci-dessus. Un tel entier nécessite deux de lecture de la mémoire de cycle pour extraire les données.
Référence: http://www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/