#pragma pack effet
Je me demandais si quelqu'un pouvait m'expliquer ce que les #pragma pack
préprocesseur déclaration, et plus important encore, pourquoi vouloir l'utiliser.
J'ai vérifié les Page MSDN, qui a donné un aperçu, mais je m'attendais à entendre plus de gens avec de l'expérience. Je l'ai vu dans le code, mais je n'arrive pas à trouver où plus.
- Elle oblige notamment l'alignement/l'emballage d'un struct, mais comme tous les
#pragma
directives, ils sont la mise en œuvre définies. A mod s = 0
où A est l'adresse et s est la taille du type de données; ceci permet de vérifier si les données ne sont pas alignés.
Vous devez vous connecter pour publier un commentaire.
#pragma pack
demande au compilateur de pack membres de structure avec notamment l'alignement. La plupart des compilateurs, lorsque vous déclarez une structure, va insérer un rembourrage entre les membres afin de s'assurer qu'ils correspondent aux adresses appropriées dans la mémoire (en général un multiple du type de la taille). Cela permet d'éviter la dégradation de la performance (ou une erreur pure et simple) sur certaines architectures associées à l'accès aux variables qui ne sont pas alignés correctement. Par exemple, étant donné entiers de 4 octets, et la structure suivante:Le compilateur pourrait choisir de jeter la structure en mémoire comme ceci:
et
sizeof(Test)
serait de 4 × 3 = 12, même si elle ne contient que 6 octets de données. L'utilisation la plus courante de cas pour la#pragma
(à ma connaissance), c'est quand travail avec les périphériques matériels où vous devez vous assurer que le compilateur ne pas insérer de rembourrage dans les données et chaque membre suit la précédente. Avec#pragma pack(1)
, la structure ci-dessus seraient disposés comme ceci:Et
sizeof(Test)
serait de 1 × 6 = 6.Avec
#pragma pack(2)
, la structure ci-dessus seraient disposés comme ceci:Et
sizeof(Test)
serait de 2 × 4 = 8.Ordre des variables dans la structure est également important. Avec des variables ordonnées comme suit:
et avec
#pragma pack(2)
, la structure serait disposé comme ceci:et
sizeOf(Test)
serait de 3 × 2 = 6.#pragma pack(2)
vous donner?#pragma
est utilisé pour envoyer des non-portable (comme en ce compilateur ne) messages du compilateur. Des choses comme la désactivation de certaines mises en garde et d'emballage des structures sont des raisons communes. La désactivation des avertissements spécifiques est particulièrement utile si vous compilez avec les mises en garde que des erreurs drapeau activé.#pragma pack
est spécifiquement utilisé pour indiquer que la structure d'être emballés ne devrait pas avoir de ses membres alignés. C'est utile lorsque vous avez mappé en mémoire de l'interface à un morceau de matériel et doivent être en mesure de contrôler exactement où les différentes les membres de la structure point. Il n'est notamment pas une bonne optimisation de la vitesse, puisque la plupart des machines sont beaucoup plus rapides à traiter avec des données alignées.Il indique au compilateur de la frontière pour aligner des objets dans une structure. Par exemple, si j'ai quelque chose comme:
Typique d'une machine 32 bits, que vous auriez normalement "envie" d'avoir 3 octets de remplissage entre
a
etb
de sorte queb
de la terre à une limite de 4 octets pour maximiser sa vitesse d'accès (et c'est ce qui est en général le cas par défaut).Si, toutefois, vous devez faire correspondre un externe définie structure vous voulez vous assurer que le compilateur dispose votre structure exactement selon cette définition externe. Dans ce cas, vous pouvez donner le compilateur un
#pragma pack(1)
dire pas pour insérer une marge entre les membres -- si la définition de la structure comprend un rembourrage entre les membres, de l'insérer de façon explicite (p. ex., généralement avec des membres nommésunusedN
ouignoreN
, ou quelque chose de cet ordre).b
à une limite de 4 octets signifie que le processeur peut charger par l'émission d'un seul de 4 octets de la charge. Bien que cela dépend un peu sur le processeur, si c'est à un étrange frontière, il ya une bonne chance que le chargement il faudra le processeur d'émettre des deux instructions de chargement, puis d'utiliser un levier de vitesses à mettre ces morceaux ensemble. Typique de la pénalité est de l'ordre de 3x plus lent de charge de l'élément.Éléments de données (par exemple, des membres de classes et les structures) sont généralement alignés sur WORD ou DWORD les limites de l'actuelle génération de processeurs, afin d'améliorer les temps d'accès. Récupération d'un DWORD à une adresse qui n'est pas divisible par 4, il faut au moins un cycle du PROCESSEUR sur un 32 bits processeur. Donc, si vous avez par exemple trois char membres
char a, b, c;
, en fait, ils ont tendance à prendre 6 ou 12 octets de stockage.#pragma
vous permet d'outrepasser cette fonction pour obtenir plus efficace l'utilisation de l'espace, au détriment de la vitesse d'accès, ou pour des raisons de cohérence de données entre les différents compilateur cibles. J'ai eu beaucoup de plaisir avec cette transition à partir de 16 bits à 32 bits de code; j'attends le portage 64 bits code provoque le même genre de maux de tête pour un peu de code.char a,b,c;
, en général, 3 ou 4 octets de stockage (sur x86 au moins) - c'est parce que leur alignement exigence est de 1 octet. Si ce n'était pas le cas, alors comment voulez-vous faire face avecchar str[] = "foo";
? L'accès à unchar
est toujours un simple fetch-maj-masque, alors que l'accès à unint
peut être récupérer-récupérer-fusion ou d'extraire seulement, selon qu'il est aligné ou pas.int
a (x86) 32 bits (4 octets) alignement parce que sinon, vous obtiendrez à (dire) une demi -int
dans unDWORD
et l'autre moitié dans l'autre, et qui prendrait les deux recherches.Un compilateur peut place membres de structure sur les limites d'octets pour des raisons de performance sur une architecture particulière. Cela peut laisser inutilisé rembourrage entre les membres. La Structure de l'emballage, les membres des forces pour être contiguës.
Cela peut être important pour exemple, si vous avez besoin d'une structure pour se conformer à un fichier en particulier ou de communication où les données dont vous avez besoin de données pour être à des positions spécifiques dans une séquence. Cependant, une telle utilisation ne traite pas avec endian-ness, de sorte que, bien utilisé, il peut ne pas être portable.
Il peut aussi exactement la superposition de registre interne de la structure de certains périphériques d'e/S comme un UART ou contrôleur USB par exemple, afin que l'accès de registre par le biais d'une structure plutôt que des adresses directes.
Compilateur pourrait aligner membres dans les structures pour obtenir des performances maximales sur certaines plate-forme.
#pragma pack
directive permet de contrôler l'alignement. Habituellement, vous devez la laisser par défaut pour des performances optimales. Si vous avez besoin de passer d'une structure à la machine distante en général, vous utiliserez#pragma pack 1
à exclure les indésirables de l'alignement.Vous auriez probablement souhaitez uniquement utiliser cette fonction si vous étiez le codage de certains matériels (par exemple, une mémoire périphérique mappé) qui avait des exigences strictes pour enregistrer la commande et de l'alignement.
Cependant, cela ressemble à un joli outil émoussé pour parvenir à cette fin. Une meilleure approche serait de coder un mini-pilote en assembleur et de lui donner un appel C interface plutôt que de tâtonner avec cette pragma.
J'ai utilisé dans le code à l'avant, mais seulement à l'interface avec le code existant. C'était un Mac OS X, Cocoa application nécessaire pour charger les fichiers de préférences à partir d'une version antérieure, version Carbone (qui était lui-même vers l'arrière-compatible avec l'original M68k Système version 6.5...vous voyez l'idée). Les fichiers de préférence dans la version originale ont été un vidage binaire de configuration, la structure, qui a utilisé le
#pragma pack(1)
pour éviter de prendre de l'espace supplémentaire et d'économie d'ordure (c'est à dire les octets de remplissage qui serait autrement dans la structure).Les auteurs du code ont également utilisé
#pragma pack(1)
pour stocker des structures qui ont été utilisés comme des messages de communication inter-processus. Je pense que la raison ici est d'éviter la possibilité d'inconnu ou changé rembourrage tailles, comme le code regardait parfois à une partie spécifique du message struct en comptant le nombre d'octets depuis le début (ewww).J'ai vu des gens l'utiliser pour faire en sorte qu'une structure est toute la ligne de cache pour éviter les faux partage dans un contexte multithread. Si vous allez avoir un grand nombre d'objets qui vont être vaguement emballé par défaut, il peut économiser de la mémoire et améliorer les performances du cache pour les emballer serré, bien que non alignés d'accès à la mémoire sera généralement ralentir les choses donc il y aura peut être un inconvénient.
Noter qu'il existe d'autres moyens d'assurer la cohérence des données qu' #pragma pack offre (par exemple, certaines personnes utilisent le #pragma pack(1) pour les structures qui doivent être envoyés à travers le réseau). Par exemple, voir le code suivant et de sa sortie:
La sortie est comme suit:
sizeof(struct a): 15, sizeof(struct b): 24
sizeof(twoa): 30, sizeof(twob): 48
Remarquez comment la taille de la structure est exactement ce que le nombre d'octets est, mais struct b a le rembourrage (voir cette pour plus de détails sur le rembourrage). En faisant cela, contrairement à la directive #pragma pack vous pouvez avoir le contrôle de la conversion du fil "format" dans les types appropriés. Par exemple, "le char de deux[2]" dans une "short int" et cetera.
sizeof
renvoie unesize_t
qui doit être imprimé à l'aide de%zu
. L'utilisation de la mauvaise spécificateur de format invoque un comportement indéfini