42 votes

Est-ce que struct packing est déterministe?

Par exemple, disons que j'ai deux structures équivalentes a et b dans différents projets:

 typedef struct _a
{
    int a;
    double b;
    char c;
} a;

typedef struct _b
{
    int d;
    double e;
    char f;
} b;
 

En supposant que je n'ai utilisé aucune directive telle que #pragma pack et que ces structures soient compilées sur le même compilateur sur la même architecture, auront-elles un remplissage identique entre les variables?

55voto

rici Points 45980

Le compilateur est déterministe; si ce n'était pas le cas, compilation séparée serait impossible. Deux unités de traduction avec le même struct déclaration de travailler ensemble; qui est garanti par l' §6.2.7/1: Compatible avec les types et les types de composé.

En outre, deux des compilateurs différents sur la même plate-forme doit interagir, même si cela n'est pas garanti par la norme. (C'est une qualité de mise en œuvre de problème). Pour permettre l'interopérabilité, les rédacteurs du compilateur d'accord sur une plate-forme de l'ABI (Application Binary Interface) qui inclut une spécification précise de la façon dont composite types sont représentés. De cette façon, il est possible pour un programme compilé avec un compilateur à l'utilisation de la bibliothèque de modules compilés avec un autre compilateur.

Mais vous ne sont pas seulement intéressés dans le déterminisme; vous aussi, vous souhaitez la mise en page de deux types différents d'être le même.

Selon la norme, deux struct types sont compatibles si leurs membres (pris à la commande) sont compatibles, et si leurs étiquettes et les noms des membres sont les mêmes. Depuis votre exemple structs ont différentes balises et les noms, ils ne sont pas compatibles, même si leurs membres sont les types, de sorte que vous ne pouvez pas utiliser l'un où l'autre est nécessaire.

Il peut sembler étrange que la norme prévoit que les étiquettes et les noms des membres à affecter la compatibilité. La norme exige que les membres d'une struct être énoncées dans la déclaration de l'ordre, de sorte que les noms ne peuvent pas changer l'ordre des membres au sein de la structure. Pourquoi, alors, pourraient-ils affecter rembourrage? Je ne sais pas du tout compilateur où ils le font, mais la norme de la flexibilité est basée sur le principe que les exigences devraient être le minimum nécessaire pour garantir la bonne exécution. Aliasing différemment marqués des structures n'est pas autorisée à l'intérieur d'une unité de traduction, donc il n'est pas nécessaire de tolérer entre les différentes unités de traduction. Et si le standard ne le permet pas. (Il serait légitime pour une mise en œuvre d'insérer des informations sur le type en structs'octets de remplissage, même si elle a besoin de façon déterministe ajouter rembourrage de fournir de l'espace pour de telles informations. La seule restriction est que le rembourrage ne peut pas être placé avant le premier membre d'une struct.)

Une plate-forme de l'ABI est susceptible de spécifier la mise en page d'un type composite, sans référence à son numéro de membre ou de noms. Sur une plate-forme particulière, avec une plate-forme de l'ABI, qui ont une spécification et un compilateur documenté pour se conformer à la plate-forme de l'ABI, vous pourriez vous en sortir avec de l'aliasing, mais elle ne serait pas techniquement correct, et, évidemment, les conditions préalables de le rendre portable.

15voto

Matteo Italia Points 53117

La norme elle-même ne dit rien à ce sujet, donc en principe on ne peut pas en être sûr.

Mais: probablement, votre compilateur adhère à certains ABI, communiquer autrement avec d'autres bibliothèques et avec le système d'exploitation serait un cauchemar. Dans ce dernier cas, l'ABI généralement prescrire exactement comment l'emballage des œuvres.

Par exemple:

  • sur x86_64 Linux/BSD, le SystemV AMD64 ABI est la référence. Ici (§3.1) pour chaque primitive de processeur type de données, il est détaillé à la correspondance avec le type C, de sa taille et de son alignement exigence, et il est expliqué comment utiliser ces données pour effectuer la disposition de la mémoire de bitfields, les structures et les syndicats; tout (d'ailleurs, le contenu réel de remplissage) est spécifié et déterministe. La même chose vaut pour beaucoup d'autres architectures, voir ces liens.

  • BRAS recommande à ses EABI pour ses processeurs, et il est généralement suivi par Linux et Windows; les agrégats alignement est spécifié dans "l'Appel de Procédure Standard pour l'Architecture ARM Documentation", §4.3.

  • sur Windows il n'y a pas de contre-standard du fournisseur, mais VC++ essentiellement dicte l'ABI, dont pratiquement n'importe quel compilateur adhérer; il peut être trouvé ici pour x86_64, ici pour les BRAS (mais pour la partie de l'intérêt de cette question renvoie à l'architecture ARM EABI).

10voto

cmaster Points 7460

Toute sane compilateur produira identiques disposition de la mémoire pour les deux structures. Les compilateurs sont généralement écrites comme parfaitement déterministe des programmes. Le Non-déterminisme devra être ajouté explicitement et délibérément, et je ne vois pas l'intérêt de le faire.

Toutefois, cela ne veut pas vous permettre de jeter un struct _a* d'un struct _b* et d'accéder à ses données via les deux. Autant que je sache, ce serait encore une violation de la stricte aliasing règles, même si la disposition de la mémoire est identique, car cela permet au compilateur de réorganiser les accès via l' struct _a* avec des accès via l' struct _b*, ce qui aurait pour résultat imprévisible, un comportement indéfini.

8voto

David Haim Points 3696

seront-ils identiques rembourrage entre les variables?

Dans la pratique, pour la plupart ils aiment avoir la même disposition de la mémoire.

En théorie, car le standard ne veut pas dire grand-chose sur la façon de rembourrage doivent être employées sur les objets, vous ne pouvez pas vraiment assumer quoi que ce soit sur la marge entre les éléments.

Aussi, je ne vois pas encore pourquoi voudriez-vous connaître et assumer quelque chose à propos de la marge entre les membres d'une structure. simplement écrire standard, conforme à C de code et vous serez amende.

5voto

Frankie_C Points 2349

Vous ne pouvez pas l'approche déterministe de la disposition d'une structure ou d'une union en langage C sur des systèmes différents.

Alors que de nombreuses fois, il pourrait sembler que la mise en page généré par les différents compilateurs est le même, vous devez prendre en compte le cas d'une convergence dictées par la pratique et fonctionnel de la commodité de la conception du compilateur dans le cadre du choix de liberté laissée au programmeur par la norme, et donc pas efficace.

Le C11 norme ISO/IEC 9899:2011, pratiquement inchangé depuis les normes précédentes, clairement indiqué dans le paragraphe 6.7.2.1 de la Structure et de l'union des prescripteurs:

Chaque non-bits membre d'une structure ou d'une union de l'objet est aligné dans une mise en œuvre définies de manière adaptée à son type.

Pire encore, le cas de bitfields où une grande autonomie est laissée au programmeur:

Une mise en œuvre peut attribuer tous adressable de l'unité de stockage assez grand pour contenir un champ de bits. Si il reste suffisamment d'espace, un peu de champ qui suit immédiatement un autre bit-champ dans une structure doivent être emballées dans les bits de la même unité. Si l'espace est insuffisant reste, si un peu de champ qui ne correspond pas à y mettre de l'unité ou des chevauchements unités adjacentes est mise en œuvre définies. La commande de l'allocation de bit-domaines au sein d'une unité (d'ordre élevé à faible ou faible afin d'ordre élevé) est mise en œuvre définies. L'alignement de la adressable de l'unité de stockage est indéterminé.

Juste compter combien de fois les conditions de mise en œuvre définies par l'' et 'non spécifié' apparaissent dans le texte.

Convenu que pour vérifier la version de compilateur, de la machine et de l'architecture cible de chaque course avant d'utiliser la structure ou de l'union généré sur un système différent est hors de prix , vous devriez avoir reçu un décent réponse à votre question.

Maintenant, disons que oui, il est un moyen de autour de.

Être clair que ce n'est certainement pas la solution, mais c'est une approche commune que vous pouvez trouver autour lorsque les structures de données exchange est partagée entre les différents systèmes: pack d'éléments de structure sur la valeur 1 (standard char de taille).

L'utilisation de l'emballage et de l'exacte définition de la structure peut conduire à un niveau suffisamment fiable déclaration qui peut être utilisé sur différents systèmes. L'emballage force le compilateur à supprimer la mise en œuvre définies alignements, de réduire les éventuelles incompatibilités en raison de la norme. En outre, en évitant d'utiliser bitfields vous pouvez enlever les résidus de mise en œuvre dépend des incohérences. Dernière, l'efficacité d'accès, en raison du manque d'alignement peut être recréé en ajoutant manuellement certains mannequin de déclaration entre les deux éléments, conçu de telle manière à force de chaque champ dans l'alignement correct.

Comme résidu des cas, vous devez tenir compte d'un rembourrage à la structure de la fin que certains compilateurs ajouter, mais parce qu'il n'est pas utile de données associées, vous pouvez l'ignorer (sauf pour la dynamique de répartition de l'espace, mais encore une fois, vous pouvez traiter avec elle).

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