Question

Je suis portage d'une application à une plate-forme ARM en C, l'application fonctionne également sur un processeur x86, et doit être rétrocompatible.

J'ai maintenant quelques problèmes avec l'alignement des variables. J'ai lu le manuel gcc __attribute__((aligned(4),packed)) J'interprète ce qui est dit que le début de la struct est aligné sur le boundry 4 octets et l'intérieur reste intacte en raison de la déclaration remplie.

à l'origine je devais cela, mais parfois il est placé non aligné avec la limite de 4 octets.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

donc je changer à cela.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((aligned(4),packed)) CHALLENGE;

Le comprendre je l'ai dit plus tôt semble être incorrect à la fois comme struct est maintenant aligné sur une limite de 4 octets, et et les données à l'intérieur est maintenant aligné sur une limite de quatre octets, mais à cause de la endianess, la taille de la struct a augmenté en taille de 42 à 44 octets. Cette taille est critique que nous avons d'autres applications qui dépendent de la structure étant de 42 octets.

Aurait-on pour me décrire comment effectuer l'opération que j'ai besoin. Toute aide est très appréciée.

Était-ce utile?

La solution

Si vous êtes en fonction de sizeof(yourstruct) être 42 octets, vous êtes sur le point d'être mordu par un monde d'hypothèses non portables. Vous avez pas dit ce que cela est pour, mais il semble probable que le boutisme des contenus struct questions aussi bien, de sorte que vous pouvez également avoir un décalage avec le x86 aussi.

Dans cette situation, je pense que le seul moyen infaillible de faire face est d'utiliser unsigned char[42] dans les régions où il importe. Commencez par écrire une spécification précise exactement quels domaines sont ceux où dans ce bloc de 42 octets, et ce endian, utilisez cette définition pour écrire un code pour traduire entre cela et un struct vous pouvez interagir avec. Le code sera probablement soit tout à la fois code-sérialisation (alias de triage), ou un groupe de accesseurs.

Autres conseils

Ceci est une raison pour laquelle tout le lecture struct au lieu de ne membre à membre, et devrait être évitée.

Dans ce cas, l'emballage ainsi que l'alignement à 4 signifie qu'il y aura deux octets de remplissage. Cela se produit parce que la taille doit être compatible pour stocker le type dans un tableau avec tous les éléments encore alignés à 4.

J'imagine que vous avez quelque chose comme:

read(fd, &obj, sizeof obj)

Parce que vous ne voulez pas lire ces 2 octets de remplissage qui appartiennent à des données différentes, vous devez spécifier explicitement la taille:

read(fd, &obj, 42)

Que vous pouvez garder maintenable:

typedef struct {
  //...
  enum { read_size = 42 };
} __attribute__((aligned(4),packed)) CHALLENGE;

// ...

read(fd, &obj, obj.read_size)

Ou, si vous ne pouvez pas utiliser certaines fonctionnalités de C ++ dans C:

typedef struct {
  //...
} __attribute__((aligned(4),packed)) CHALLENGE;
enum { CHALLENGE_read_size = 42 };

// ...

read(fd, &obj, CHALLENGE_read_size)

A la prochaine occasion de refactoring, je vous suggère fortement de commencer à lire chaque membre individuellement, qui peut facilement être encapsulé dans une fonction.

Quel est votre véritable objectif?

S'il est de traiter les données qui se trouve dans un fichier ou sur le fil dans un format particulier ce que vous devez faire est d'écrire quelques marshaling / routines de sérialisation qui se déplacent les données entre le struct du compilateur qui représente la façon dont vous voulez faire face à la données à l'intérieur du programme et un tableau de caractères qui traite de la façon dont les données semble sur le fil / fichier.

Ensuite, tout ce qui doit être traitée avec soin et peut-être avoir un code spécifique de la plate-forme est les routines de marshaling. Et vous pouvez écrire des tests unitaires nice-n-nasty pour faire en sorte que les données marshalés arrive à et de la struct correctement, peu importe quelle plate-forme que vous pourriez avoir au port aujourd'hui et dans l'avenir.

J'ai été le déplacement des structures avant et en arrière de Linux, Windows, Mac, C, Swift, Assemblée, etc.

Le problème n'est pas qu'il ne peut pas être fait, le problème est que vous ne pouvez pas être paresseux et devez comprendre vos outils.

Je ne vois pas pourquoi vous ne pouvez pas utiliser:

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

peut utiliser et ne nécessite pas de code spécial ou intelligent. Je vous écris beaucoup de code qui communique avec ARM. Les structures sont ce qui rend les choses fonctionnent. __attribute__ ((packed)) est mon ami.

Les chances d'être dans un « monde de douleur » sont nulles si vous comprenez ce qui se passe avec les deux.

Enfin, je ne peux pas pour la vie faire savoir comment vous obtenez 42 ou 44. Int est soit 4 nos 8 octets (en fonction du compilateur). Cela met le nombre à chaque 16 + 16 + 2 = 34 ou 32 + 16 + 2 = 50 -. En supposant qu'il est vraiment emballé

Comme je le dis, sachant que vos outils fait partie de votre problème.

Je suppose que le problème est que 42 est divisible par 4, et donc ils sortir de l'alignement si vous mettez plusieurs de ces struct dos à dos (par exemple allouer de la mémoire pour plusieurs d'entre eux, déterminer la taille avec sizeof ). Avoir la taille 44 force l'alignement dans ces cas que vous avez demandé. Toutefois, si le décalage interne de chaque membre struct reste le même, vous pouvez traiter le struct 44 octets comme si elle était de 42 octets (aussi longtemps que vous prenez soin d'aligner les données suivantes à la limite correcte).

Une astuce pour essayer peut-être mettre à la fois de ces struct l'intérieur d'un seul type d'union et d'utiliser uniquement la version 42 octets à partir de chaque union.

Comme j'utilise linux, j'ai trouvé que par echo 3 > /proc/cpu/alignment il me délivrera un avertissement, et résoudre le problème d'alignement. Ceci est un travail autour, mais il est très utile à la localisation où les structures ne parviennent pas à être désaligné.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top