99 votes

C struct mémoire mise en page?

J'ai le C# arrière-plan. Très débutant de langage de bas niveau comme le C.

En C#, structure de la mémoire fixées par le compilateur par défaut. Compilateur pouvez changer l'ordre des champs de données ou la tablette des bits supplémentaires entre les champs implicitement. J'ai donc dû spécifier un attribut spécial de modifier ce comportement pour la mise en page exacte.

Autant que je sache, C n'a pas de réorganiser ou de l'aligner disposition de la mémoire d'une structure par défaut. Mais j'ai entendu il ya un peu d'exceptions qui sont très difficiles à trouver.

Qu'est-ce que C est à disposition de la mémoire de comportement? (ce qui devrait être re-commandé/alignés et non)

143voto

dan04 Points 33306

C'est spécifique à l'implémentation, mais dans la pratique, la règle (en l'absence d' #pragma pack ou similaires):

  • Les membres de la structure sont stockés dans l'ordre où elles sont déclarées. (Ceci est requis par le standard C99, comme mentionné ici plus tôt.)
  • Si nécessaire, le rembourrage est ajouté avant chaque structure membre, pour assurer l'alignement correct.
  • Chaque type primitif T nécessite un alignement de l' sizeof(T) octets.

Donc, compte tenu de la structure:

struct ST
{
   char ch1;
   short s;
   char ch2;
   long long ll;
   int i;
};
  • ch est à l'offset 0
  • un rembourrage octet est inséré à aligner...
  • s au décalage de 2
  • ch2 est à l'offset 4, immédiatement après s
  • 3 octets de remplissage sont insérés aligner...
  • ll à décalage 8
  • je est au décalage de 16 ans, juste après ll
  • 4 octets de remplissage sont ajoutés à la fin de sorte que l'ensemble de la structure est un multiple de 8 octets. J'ai vérifié cela sur un système 64 bits: 32 bits des systèmes peut permettre à des structures de disposer de 4 octets de l'alignement.

Donc, sizeof(ST) est de 24.

Elle peut être réduite à 16 octets en réorganisant les membres à éviter padding:

struct ST
{
   long long ll; // @ 0
   int i;        // @ 8
   short s;      // @ 12
   char ch1;     // @ 14
   char ch2;     // @ 15
} ST;

120voto

Potatoswatter Points 70305

En C, le compilateur est autorisé à dicter certaines d'alignement pour chaque type primitif. Généralement, l'alignement est la taille du type. Mais il est tout à fait spécifique à l'implémentation.

Les octets de remplissage sont mis en place afin que chaque objet est correctement aligné. La réorganisation n'est pas autorisé.

Éventuellement, tous à distance moderne compilateur implémente #pragma pack qui permet de contrôler plus de rembourrage et laisse au programmeur de se conformer à l'ABI. (Il est strictement non standard, cependant).

De C99 §6.7.2.1:

12 Chaque non-bits membre d'un la structure ou union de l'objet est aligné la mise en œuvre définies de manière approprié à son type.

13 Dans un la structure de l'objet, de la non-bits les membres et les unités dans lesquelles peu de champs de résident ont des adresses qui augmentation de l'ordre dans lequel ils sont déclarés. Un pointeur vers une structure objet, convenablement convertis, les points de son premier membre (ou, si ce membre c'est un peu de champ, puis à l'unité lequel il se trouve), et vice-versa. Il peut être sans nom rembourrage à l'intérieur d'un la structure de l'objet, mais pas à sa début.

13voto

jschmier Points 8088

Vous pouvez commencer par la lecture de la structure des données de l'alignement de l'article de wikipédia pour obtenir une meilleure compréhension de l'alignement des données.

À partir de l' article de wikipédia:

L'alignement des données signifie mettre les données à un offset de mémoire égale à un multiple de la taille de mot, ce qui augmente les performances du système en raison de la façon dont le CPU gère la mémoire. Pour aligner les données, il peut être nécessaire d'insérer quelques pas de sens octets entre la fin de la dernière structure de données et le début de la prochaine, qui est une structure de données de remplissage.

De 6.54.8 Structure d'Emballage des Pragmas de la GCC de la documentation:

Pour la compatibilité avec Microsoft Windows de compilateurs GCC prend en charge un ensemble de #pragma directives qui changent la maximum de l'alignement des membres de structures (autre que zéro-largeur bitfields), les syndicats, et les classes par la suite défini. La valeur de n ci-dessous est toujours nécessaire d'être un petit une puissance de deux et spécifie le nouveau l'alignement en octets.

  1. #pragma pack(n) définit simplement le nouvel alignement.
  2. #pragma pack() définit l'alignement de celui qui était dans l' effet lors de la compilation de démarrage (voir aussi l'option de ligne de commande -fpack-struct[=] voir le Code Gen Options).
  3. #pragma pack(push[,n]) pousse l'alignement en cours de réglage sur une la pile interne et, éventuellement, définit le nouvel alignement.
  4. #pragma pack(pop) restaure les paramètres d'alignement à celui enregistré au le haut de la pile interne (et enlève la pile d'entrée). Notez que enter code here#pragma pack([n]) n'a pas d'influence sur la pile interne; il est donc possible d'avoir #pragma pack(push) suivie par de multiples #pragma pack(n) les instances et finalisé par un seul #pragma pack(pop).

Certains objectifs, par exemple les architectures i386 et powerpc, l'appui de la ms_struct #pragma qui dispose d'une structure comme l'a documenté _attribute_ ((ms_struct)).

  1. #pragma ms_struct dans les virages sur la mise en page pour les structures déclaré.
  2. #pragma ms_struct off désactive la mise en page pour les structures déclaré.
  3. #pragma ms_struct réinitialiser remonte à la disposition par défaut.

4voto

SoapBox Points 14183

En C, les structures sont disposées presque exactement comme vous le spécifier dans le code. Similaire à C#'s StructLayout.Séquentielle.

La seule différence est membre de l'alignement. Jamais cela ne réordonne les membres de données dans une structure, mais vous pouvez modifier la taille de la structure par insertion de "pad" octets dans le milieu de la structure. La raison pour cela est de s'assurer que chacun des membres commence sur une limite (généralement 4 ou 8 octets).

Par exemple:

struct mystruct {
   int a;
   short int b;
   char c;
};

La taille de cette structure sera généralement de 12 octets (4 pour chaque membre). C'est parce que la plupart des compilateurs, par défaut, chaque membre de la même taille que le plus important dans la structure. De sorte que le char va prendre jusqu'à 4 octets au lieu d'un. Mais il est très important de noter que sizeof(mystruct::c) sera toujours de 1, mais sizeof(mystruct) sera de 12.

Il peut être difficile de prévoir comment la structure sera rembourré/aligné par le compilateur. La plupart seront par défaut comme je l'ai expliqué ci-dessus, certains sera, par défaut, pas de rembourrage/alignement (parfois également appelé "paniers").

La méthode pour modifier ce comportement est très dépendant du compilateur, il n'y a rien dans le langage de spécification de la manière dont cela doit être traitée. Dans MSVC vous utilisez #pragma pack(1) pour désactiver l'alignement (le 1 dit aligner tout sur 1 les limites d'octets). DANS GCC, vous utiliserez __attribute__((packed)) dans la définition de la structure. Consultez la documentation de votre compilateur pour voir ce qu'il fait par défaut et comment changer ce comportement.

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