2010-04-17 11 views
13

Je sais qu'un char et un int sont calculés comme étant 8 octets sur des architectures 32 bits en raison de l'alignement, mais je suis récemment tombé sur une situation où une structure avec 3 courts métrages a été rapportée comme étant 6 octets par l'opérateur sizeof. Le code est le suivant:Comment sizeof calcule la taille des structures

#include <iostream> 
using namespace std ; 

struct IntAndChar 
{ 
    int a ; 
    unsigned char b ; 
}; 


struct ThreeShorts 
{ 
    unsigned short a ; 
    unsigned short b ; 
    unsigned short c ; 
}; 


int main() 
{ 
    cout<<sizeof(IntAndChar)<<endl; // outputs '8' 
    cout<<sizeof(ThreeShorts)<<endl; // outputs '6', I expected this to be '8' 
    return 0 ; 
} 

Compilateur: g ++ (Debian 4.3.2-1.1) 4.3.2. Cela me laisse vraiment perplexe, pourquoi l'alignement n'est-il pas appliqué à la structure contenant 3 courts métrages?

Répondre

21

En effet, int est de 4 octets et doit être aligné sur une limite de 4 octets. Cela signifie que tout struct contenant un int doit également être aligné sur au moins 4 octets.

D'autre part, short est de 2 octets et n'a besoin d'être aligné que sur une limite de 2 octets.Si un struct contenant short s ne contient rien qui nécessite un alignement plus grand, le struct sera également aligné sur 2 octets.

2

Il est entièrement mise en œuvre dépendant, mais probablement si votre système peut accéder à l'une des trois short s dans la struct sans se soucier de l'alignement, il peut accéder à tous les short, et par conséquent tout membre de données, dans un tableau de ThreeShorts sans s'inquiéter de l'alignement. Par conséquent, il n'est pas nécessaire d'aligner les structures plus strictement.

Pour l'exemple IntAndChar, int a sans doute la taille 4 et la mise en œuvre est concerné par son alignement. Pour s'assurer que chaque membre int dans un tableau de IntAndChar est correctement aligné, la structure doit être complétée.

Le sizeof un tableau T[n] est exactement défini comme sizeof(T) * n.

15

Cela me laisse vraiment perplexe, pourquoi l'alignement ne sont pas appliquées pour les t

Quel alignement voulez-vous qu'il ait?

Les courts métrages peuvent être alignés sur des limites de 2 octets sans effets négatifs (en supposant que les compilateurs x86 courants sont partout ici). Donc, si vous créez un tableau de struct ThreeeShorts, cette structure ayant une taille de 6 est correcte, car tous les éléments d'un tel tableau démarreront sur une limite de 2 octets.

Votre struct IntAndChar contient un int, ints veut un alignement de 4 octets, donc si vous créez un tableau de struct IntAndChar la taille doit être 8 pour que l'élément suivant soit aligné sur une limite de 4 octets. Si nous ne considérions pas les tableaux, peu importe si struct IntAndChar avait une longueur de 5 octets, le compilateur l'attribuerait à partir d'une limite de 4 octets lorsque vous en créeriez un ou l'utiliseriez comme membre composé dans une autre structure. Vous pouvez toujours obtenir le nombre d'éléments dans un tableau en faisant sizeof (arrayofT)/sizeof (T), et les éléments du tableau sont garantis d'être stockés de façon adjacente, de sorte que le nième élément peut être récupéré par pas N * sizeof (arrayelementtype) octets depuis le début, et c'est la raison principale pour laquelle les structures seront complétées à la fin.
+0

Ce n'est pas que je veuille un alignement particulier, c'est juste que je pensais que l'alignement de 4 octets était toujours respecté sur les architectures 32 bits –

+0

Si seulement! Il serait certainement beaucoup plus facile d'écrire des allocateurs de mémoire ...Malheureusement, l'alignement peut différer d'un type à l'autre et il n'y a aucune manière portable de demander au compilateur l'alignement particulier d'un type donné, bien qu'il y ait des astuces. –

+0

'#define aligner (type) ((char *) & ((struct {char dummy; type x;} *) 0) -> x - (char *) 0)' –

6

Je ne sais pas d'où vient l'idée que char ou int est calculé comme "8 octets". Non, chaque type est calculé en fonction de sa taille: char comme 1, int comme 4 sur une plate-forme 32 bits (pas 8, mais 4). L'exigence d'alignement pour chaque type est normalement la même que sa taille (bien que cela ne soit pas obligatoire).

Pour cette raison, lorsque la structure contient les membres du même type, la taille totale de cette structure sera normalement la somme exacte des tailles de ses membres: une structure de 3 char s auront la taille 3 et la structure de deux int s aura la taille 8.

Apparemment, tapez short sur votre plate-forme a la taille 2, donc, normalement, une structure de 3 courts métrages a la taille 6, ce qui est exactement ce que vous observez.

Toutefois, lorsque votre structure contient des membres de différents types, la différence entre les exigences d'alignement de différents types entre en jeu. Si l'exigence d'alignement du champ suivant est plus stricte que l'exigence d'alignement du champ précédent, le compilateur peut devoir ajouter des octets de remplissage entre ces champs (pour aligner correctement le membre suivant), ce qui affectera la taille finale de la structure. En outre, le compilateur peut avoir à ajouter des octets de remplissage supplémentaires après le dernier membre de la structure pour satisfaire les exigences d'alignement dans un tableau.

Par exemple, une structure qui se présente comme suit

struct S { 
    char c; 
    int i; 
}; 

occupera probablement 8 octets sur votre plate-forme en raison de la nécessité de 3 octets de remplissage après que le membre char. Remarque, char compte comme 1, int comme 4 et les 3 octets de rembourrage supplémentaire entre les rendre 8.

Notez également que cela pourrait facilement introduire la dépendance de la taille finale de la structure de l'ordre dans lequel les membres sont déclaré. Par exemple, cette structure

struct S1 { 
    char c1; 
    int i; 
    char c2; 
}; 

sur votre plate-forme aura probablement la taille 12, alors que celui-ci

struct S2 { 
    int i; 
    char c1; 
    char c2; 
}; 

occupera seulement 8 octets. Ce dernier exemple est destiné à illustrer que la taille finale de la structure ne peut pas être exprimée en termes de nombre d'octets pour lesquels chaque membre "compte". Les relations entre les membres sont également importantes.

1

Oui, j'avais le même problème. J'ai la structure suivante

struct Node{ 
    short digit; 
    Node* next; 
}; 
    cout<<":"<<sizeof(Node)<<":"<<sizeof(short)<<":"<<sizeof(Node*)<<endl; 

Cela me donne :: 8: 2: 4 ?? pourquoi la somme totale pour la structure = 8, mais les éléments individuels ne résument pas ?? En raison de l'alignement de la mémoire, la mémoire est complétée avec 2 octets supplémentaires pour l'alignement. Merci