Est-il prudent d’utiliser des membres de structure comme références à des décalages de mémoire?

Sur le site du centre d’information ARM, ils ont suggéré d’utiliser des structures pour mapper les variables aux adresses mémoire.

#define PORTBASE 0x40000000 typedef struct Port { uint32_t reg0; uint32_t reg1; uint32_t reg2; } Port; volatile struct Port * const reg_p = (struct Port *)PORTBASE; 

Cependant, j’ai vu quelqu’un d’autre suggérer que les compilateurs puissent append du rembourrage entre les membres d’un object struct et le seul moyen d’éviter que cela ne se produise consiste à utiliser l’atsortingbut __atsortingbute__((__packed__)) , comme dans GCC __atsortingbute__((__packed__)) , par exemple.

Il me semble que le compilateur introduirait uniquement un bourrage pour aligner les limites des membres, mais je ne vois pas dans la norme C99 qu’il indique explicitement que cela ne devrait pas se produire dans d’autres cas. En fait, il semble que cela puisse arriver.

À partir de la section 6.7.2.1 du C99,

12

Chaque membre de champ non binary d’un object structure ou union est aligné d’une manière définie par l’implémentation et adaptée à son type.

13

Dans un object de structure, les membres autres que les champs de bits et les unités dans lesquelles résident les champs de bits ont des adresses qui augmentent dans l’ordre dans lequel ils ont été déclarés. Un pointeur sur un object de structure, converti de manière appropriée, pointe vers son membre initial (ou si ce membre est un champ de bits, puis vers l’unité dans laquelle il réside), et inversement. Il peut y avoir un remplissage non nommé dans un object de structure, mais pas au début.

15

Il peut y avoir un remplissage non nommé à la fin d’une structure ou d’une union.

Étant donné l’exemple ci-dessus, est-il garanti que reg1 sera exactement décalé de 32 bits par rapport à reg0 sans dire au compilateur de ne pas append de remplissage?

Le remplissage entre les membres est ajouté, de sorte que les valeurs soient alignées sur 32 bits (selon l’architecture). Par exemple, un uint32_t doit commencer à un décalage aligné de 4 * 2 ^ x pour être plus rapidement accessible puis se compose uniquement de valeurs 32 bits, ceci est automatiquement vrai si PORTBASE est une adresse alignée.

Par conséquent, le compilateur ne doit dans ce cas pas append de remplissage, mais vous pouvez toujours append

 __atsortingbute__((__packed__)) 

pour être sûr.

Le compilateur appendait du rembourrage dans les cas suivants:

 struct { uint8_t a; uint32_t b; } 

où b se retrouverait sur une adresse non alignée.

Le problème est que pour arm, vous pourriez obtenir des compilateurs qui ne sont pas complètement compatibles C99.