40 votes

Rembourrage dans les structures en C

C'est une question d'entrevue. Jusqu'à maintenant, j'ai l'habitude de penser que ces questions ont été purement compilateur dépendante et ne vous inquiétez pas de moi, mais maintenant, je suis plutôt curieux.

Supposons que vous disposez de deux structures:

struct A {  
  int* a;  
  char b;  
 }  

et ,

struct B {  
  char a;  
  int* b;  
}  

Alors, qui choisiriez-vous et pourquoi? Ma réponse était comme ça (même si j'ai été un peu prise de vue dans l'obscurité) que la première structure qui doit être privilégiée car le compilateur alloue de l'espace pour une structure dans certains multiples de la taille de mot (qui est la taille du pointeur de 4 octets sur 32 bits machines et 8 octets, 64 bits). Donc, pour les deux structures, le compilateur va allouer de 8 octets(en supposant que ses un ordinateur 32 bits). Mais, dans le premier cas, le remplissage serait fait après toutes mes variables(c'est à dire après a et b). Donc, même si par hasard, b obtient une valeur qui déborde et détruit mon prochain collier octets, mais mon un est encore sûr.

Il n'a pas semblé beaucoup de plaisir et a demandé un inconvénient de la première structure au cours de la seconde. Je n'ai pas grand chose à dire. :D

Merci de m'aider avec les réponses.

34voto

MByD Points 78505

Je ne pense pas qu'il y a un avantage pour l'une de ces structures. Il y a un(!) une constante dans cette équation. L'ordre des membres de la structure est assuré d'être déclarée.

Donc, dans des cas comme celui-ci, le deuxième structure pourrait avoir un avantage, car il a probablement une plus petite taille, mais pas dans votre exemple, comme ils vont probablement avoir la même taille:

struct {
    char a;
    int b;
    char c;
} X;

Vs.

struct {
    char a;
    char b;
    int c;
} Y;

Un peu plus d'explications concernant les commentaires ci-dessous:

Tous les ci-dessous n'est pas à 100%, mais la façon dont les structures seront construites en 32 bits système où l'int de 32 bits:

Struct X:

|     |     |     |     |     |     |     |     |     |     |     |     |
 char  pad    pad   pad   ---------int---------- char   pad   pad   pad   = 12 bytes

struct Y:

|     |     |     |     |     |     |     |     |
 char  char  pad   pad   ---------int----------        = 8 bytes

11voto

cnicutar Points 98451

Certaines machines accéder à des données plus efficacement lorsque les valeurs aligné à certaines limites. Certains nécessitent des données pour être alignés.

Modernes, les machines 32 bits, comme le SPARC ou Intel [34]86, ou de toute Motorola puce de la 68020, chacun de données iten doit généralement être `auto-aligné", à partir d'une adresse qui est un multiple de sa type de taille. Ainsi, 32-bit types doit commencer sur une limite de 32 bits, 16 bits types sur la 16-bit de la frontière, 8 bits type peut commencer n'importe où, struct/tableau/types d'union ont l'alignement de leurs plus restrictif membre.

Donc vous pourriez avoir

struct B {  
    char a;
    /* 3 bytes of padding ? More ? */
    int* b;
}

Une règle simple que de minimiser le rembourrage dans les `auto-aligné" cas (et ne fait pas de mal dans la plupart des autres) est de l'ordre de votre les membres de la structure par diminution de la taille.

Je ne vois personnellement pas d'inconvénient avec la première structure par rapport au second.

4voto

Steve Jessop Points 166970

Je ne peux pas penser à un inconvénient de la première structure au cours de la deuxième dans ce cas particulier, mais il est possible de venir avec des exemples où il y a des inconvénients à la règle générale de mettre le plus grand des membres de la première:

struct A {  
    int* a;
    short b;
    A(short num) : b(2*num+1), a(new int[b]) {} 
    // OOPS, `b` is used uninitialized, and a good compiler will warn. 
    // The only way to get `b` initialized before `a` is to declare 
    // it first in the class, or of course we could repeat `2*num+1`.
}

J'ai aussi entendu parler d'un peu plus compliquée pour les grandes structures, où le PROCESSEUR est rapide modes d'adressage pour accéder au pointeur+offset, pour de petites valeurs de décalage (jusqu'à 8 bits, par exemple, ou certains autres limite d'une valeur immédiate). Vous meilleur micro-optimisation d'une grande structure en mettant de la plus couramment utilisée de champs que possible au sein de la gamme de la manière la plus rapide des instructions.

Le PROCESSEUR peut même avoir rapidement adressage de pointeur+offset et pointeur+4*décalage. Ensuite, supposons que vous avez eu 64 char champs et 64 int champs: si vous mettez le char champs d'abord, puis tous les champs de ces deux types peuvent être traitées en utilisant le meilleur des instructions, alors que si vous mettez l'int champs en premier, puis le char des champs qui ne sont pas 4-alignés juste pour être accessible différemment, peut-être par le chargement d'une constante dans un registre plutôt qu'avec une valeur immédiate, parce qu'ils sont à l'extérieur de l'256 octets limite.

N'a jamais eu à le faire moi-même, et par exemple x86 permet aux grands immédiate valeurs de toute façon. Il n'est pas le genre de l'optimisation que n'importe qui devrait normalement penser, sauf si ils passent beaucoup de temps à regarder de l'assemblée.

2voto

Alek Points 1565

Brièvement, il n'y a aucun avantage à choisir soit dans le cas général. La seule situation où le choix de la matière, dans la pratique, si la structure de l'emballage est activée, dans le cas struct A serait un meilleur choix (puisque les deux domaines seraient alignées en mémoire, tandis que dans d' struct B le b champ situé à une drôle de décalage). La Structure de l'emballage signifie qu'aucun des octets de remplissage sont insérés à l'intérieur de la structure.

Cependant, c'est plutôt rare de scénario: la structure de l'emballage est généralement activée uniquement dans des situations spécifiques. Il n'est pas un problème sur la plupart des programmes. Et il n'est pas contrôlable par le biais de n'importe quel portable de la construction dans le C standard.

1voto

Kevin Points 10204

C’est aussi une supposition, mais la plupart des compilateurs ont une option de désalignement qui n’ajoutera pas explicitement d’octets de remplissage. Cela nécessite ensuite (sur certaines plates-formes) une correction d'exécution (interruption matérielle) pour aligner les accès à la volée (avec une pénalité de performance correspondante). Si je me souviens bien, HPUX faisait partie de cette catégorie. Ainsi, la première structure des champs reste alignée même lorsque des options de compilateur mal alignées sont utilisées (car comme vous l'avez dit, le remplissage serait à la fin).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X