Effets de __attribute __ ((packed)) sur un tableau imbriqué de structures?
Le Problème
Je suis en train de travailler sur l'envoi d'une structure brute sur un réseau à un programme connu de l'autre côté, mais à vous soucier de l'silencieusement introduit la mémoire utilisée pour l'alignement des structures (d'autres problèmes comme l'endianness sont couverts). Ce que je suis en train de travailler avec quelque chose comme:
typedef struct __attribute__((packed))
{
uint16_t field1;
uint16_t field2;
uint16_t field3;
} packed_1_s;
typedef struct __attribute__((packed))
{
uint16_t fieldA;
uint16_t fieldB;
packed_1_s structArray[10];
} packed_2_s;
typedef struct __attribute__((packed))
{
uint16_t fieldX;
packed_2_s fieldY;
uint8_t arrayZ[20];
} data_s;
Je comprends que, normalement, la packed_1_s structure pourrait/aurait plus d'espace alloué pour chaque instance de la structure à remplir pour le compilateur favori taille (dépend du matériel, il est en cours de construction pour), et qui a favorisé la taille peut être n'importe où à partir de 2 octets 64 octets (plus récemment). Normalement, si j'avais une seule instance de packed_1_s dans packed_2_s il n'y aurait pas de problème, mais je me suis fait comprendre il y a quelques différences lorsque vous essayez de mettre des éléments dans un tableau.
Tentatives De Solutions
La gcc documentation semble suggérer que simplement en incluant les paniers de l'attribut dans la packed_2_s définition, les champs, même si elles sont des tableaux, seront tout aussi serrés que possible et de ne pas ajouter de l'espace pour la packed_2_s structure pour aligner les éléments de la matrice. La documentation sur les aligner() attribut mais suggère que les tableaux sont traités différemment des autres domaines, et il faut les aligner/paniers attribut défini sur le domaine directement pour modifier l'espacement supplémentaire ajouté à correspondre au spécifié à l'alignement (ou son absence). J'ai essayé le réglage de la emballés attribut à la fois sur les tableaustruct terrain, et quand ça ne marche pas, fait un test en définissant les paniers attribut sur arrayZ dans le code ci-dessus:
packed_1_s structArray[10] __attribute__((packed));
uint8_t arrayZ[20] __attribute__((packed));
Les deux tentatives m'a donné un avertissement du compilateur que les paniers attribut n'était pas comprise dans ce contexte et ignorées (bonne chose-je construire avec le "Mur").
Je l'espère, un moyen de contourner le problème serait d'utiliser l'attribut align(1), ce qui indique un alignement souhaité de 1 octet, qui est comparable à la emballés attribut, mais la documentation dit que les aligner() attribut ne peut augmentation l'alignement et emballé doit être utilisé pour diminution l'alignement.
Considérations
De ce que je peux déterminer à partir de la GCC de la documentation, il semble comme il y a 3 causes majeures de la mémoire supplémentaire à insérer.
- Structure de contenu peut avoir de la mémoire supplémentaire alloué à l'
la structure elle-même pour modifier l'espacement entre les champs.
Effectivement, la définition de la carte mémoire de la structure
contenu à l'intérieur de la structure peut changer (mais pas dans l'ordre
des éléments).- De Structures de la mémoire supplémentaire qui leur est alloué pour remplir
pour plus efficaces dans l'ensemble de la taille. Ce n'est généralement
l'intention de sorte que d'autres variables à venir après une déclaration de l'un des
leur cas ne tombe pas dans le même "bloc", comme l'
la structure de l'instance où un "bloc" est défini par le système/compilateur.- Tableaux, que ce soit au sein d'une structure ou non, peut avoir d'autres
mémoire ajoutés à déplacer les éléments à l'efficacité de l'alignement.
Aussi loin que je peux dire, les paniers attribut peut être utilisé pour modifier la structure et le bloc de la mémoire supplémentaire ajouté dans les cas 1 et 2 ci-dessus, mais il ne semble pas être un moyen pour gérer les cas 3 ci-dessus sur mon compilateur(s).
La Question
Est-il de toute façon à garantir que la data_s structure aura absolument aucun espace supplémentaire ajouté ou l'un quelconque de ses sous-structures, donc je n'ai pas de compilateur dépendante des changements dans la carte mémoire? Suis-je malentendu le cas où le compilateur peut insérer un espace, intentionnellement, maj de la carte mémoire?
MODIFIER
J'ai discuté de certains des problèmes avec mon gourou local et il semble que j'ai une certaine incompréhension de cas 3 ci-dessus. Les éléments du tableau n'avez pas l'espace à insérer entre eux, mais l'espace supplémentaire pour garantir qu'ils s'aligner correctement est ajouté à la structure elle-même. Apparemment, cela suggère des choses comme "sizeof(structureOnlyContaining_uint32_t)" ne permet pas toujours de retour "4" depuis l'espace supplémentaire peut être ajouté pour aligner les uint32_t type de données sur le compilateur utilisé. Le résultat est qu'il ya vraiment seulement 2 cas:
- Les grands décalages entre les champs de la mémoire de la carte de la structure.
L'espace entre les champs peuvent être modifiés pour s'aligner chaque champ.
Ceci peut être changé en utilisant les paniers ou les aligner() attributs.- Structure de fin de remplissage. La taille d'une structure, telle qu'elle est renvoyée par
sizeof(), peut être modifié afin de tableaux de structures en fin de
correctement alignée pour le système. Cela permet à tous les systèmes d'assumer
que le début de structures seront toujours alignés, à l'origine de problèmes
s'ils ne le sont pas. Ce ne semble pas affectée par le pack ou aligner des attributs.
En raison des nouveaux cas 2, les éléments d'un tableau dans une structure n'est pas nécessairement obéir aux paniers ou aligner() attributs spécifiés sur la structure, bien que le début du tableau et le terrain immédiatement après le tableau n'.
Ma question est donc de savoir quoi faire avec la tableaustruct dans packed_2_s depuis la taille du tableau dans son ensemble ne peut être garanti que par les paniers de l'attribut. Est-il un moyen de garantir la taille fixe de la tableaustruct champ dans son ensemble? Il convient de noter que je ne peux pas augmenter la taille de la packed_1_s trop depuis le data_s struct doit être maintenue aussi faible que possible (son remplaçant données Audio/Vidéo en streaming scénario).
source d'informationauteur mtalexan | 2011-10-31
Vous devez vous connecter pour publier un commentaire.
Noter les points suivants à propos de
__attribute__((packed))
:Quand
packed
est utilisé dans une déclaration de structure, il va compresser ses domaines, tel que, sizeof(structure) == sizeof(first_member) + ... + sizeof(last_member).Ici, un tableau est juste un membre de la struct. L'emballage contenant la structure d'un tableau ne va pas changer la taille du tableau. En fait, la taille de la (toute) la matrice est toujours sizeof(element) * number_of_elements.
De même, un emballage contenant la structure d'une structure interne ne va pas changer la taille de la structure intérieure. De la taille d'une structure est complètement déterminée par sa déclarationet est le même, peu importe où vous utilisez.
Emballage une structure fera son alignement nécessaire à un octet (c'est à dire qu'il peut être placé n'importe où dans la mémoire).
D'emballage introduire des problèmes d'alignement lors de l'accès aux champs d'une structure compacte. Le compilateur prendra en compte que lorsque les champs sont directement accessibles, mais pas quand ils sont accessibles via des pointeurs. Bien sûr, cela ne s'applique pas aux champs avec alignement nécessaire (par exemple, un char ou d'autres paniers structures). Voir ma réponse à une question similairequi comprend un programme de démonstration le problème à l'accès aux membres à l'aide de pointeurs.
Enfin, pour répondre à la question,
Oui. Déclarer la structure de paniers, et aussi toutes les structures qu'il contient, de façon récursive.
Noter également que les paniers attribut s'applique à une déclaration de structure, et non pas à un type. Il n'y a pas une telle chose comme la version compressée d'une structure qui est déclarée non-emballés. Lorsque vous utilisez une structure quelque part, il (ses membres) seront emballés si et seulement si la structure elle-même est emballé. C'est le genre de tacite par le fait que la taille de la structure est complètement déterminée par sa déclaration.
Mise à JOUR: Pour une raison quelconque vous êtes encore confus à propos des tableaux. La solution que j'ai fourni (déclarer toutes les structures emballé) travaille avec des tableaux trop. Par exemple:
Les deux autres points que vous avez fait sur les tableaux sont vrai, mais uniquement lorsque les structures ne sont pas emballés. L'emballage des forces les champs de la structure continue, et ce ne créer des problèmes d'alignement qui, si pas d'emballage a été utilisé, pourrait être résolu par l'insertion d'espace vide entre les membres et le remplissage de la structure (voir le point que j'ai déjà soulevée à propos de l'alignement).