partage de mémoire union et structure
J'essayais de trouver la réponse à une question qui implique deux structures à l'intérieur d'un syndicat.
J'ai tapé la question dans le débogueur en ligne la réponse que je trouve et la vraie réponse n'est pas de se donner la main. Quelqu'un peut-il m'aider avec la réponse avec des explications.
#include <stdio.h>
int main()
{
union{
struct{
char c[2];
char ch[2];
}s;
struct {
short int i;
short int j;
}st;
}u={12,1,15,1};
printf("%d%d",u.st.i,u.st.j);
}
la réponse est 268et271
Réponses
Les nombres décimaux ne sont pas très bons pour ce type de tests. Vous devez également activer tous les avertissements. Si vous le faites, vous obtiendrez
<source>:25:8: warning: missing braces around initializer [-Wmissing-braces]
Alors réécrivons un peu votre programme:
int main()
{
union
{
struct
{
char c[2];
char ch[2];
}s;
struct
{
short int i;
short int j;
}st;
}u={.s = {{0x12,0x01},{0x15,0x01}}}; //better to show compiler what you want to initialize
printf("%04hx %04hx",u.st.i,u.st.j);
}
Et le résultat est:
0112 0115
montrant clairement les nombres que nous avons utilisés lors de l'initialisation. Les chiffres nous montrent que ce système utilise un système little endian où l'octet le moins significatif est placé en premier.
Vous devez savoir que le compilateur est libre d'ajouter tout remplissage nécessaire. Pour éviter cela, vous devez utiliser des extensions de compilateur - l'empaquetage de structure.
- Commencez par faire plus de sens de ce en échangeant en hexadécimal:
{0xC,0x1,0xF,0x1}. Cela nous permet de visualiser les octets tels qu'ils sont stockés en mémoire, sans se soucier de la conversion vers / depuis la base décimale. - Lors de l'initialisation de a
union, le premier membre est initialisé, dans ce cas lestruct s. - Ce serait plus propre à écrire,
{ {{0xC,0x1}, {0xF,0x1}} }mais malheureusement, C permet d'omettre les accolades des structures / tableaux internes, ce qui nous permet de mettre de la merde mal écrite dans nos listes d'initialisation juste parce que nous le pouvons. - L'ordre de mémoire d'un
chartableau d'octets est toujours de haut en bas sur n'importe quel système: premier octet sur l'adresse la moins significative. C'est:0xC 0x1 0xF 0x1. - Strictement parlant, le compilateur est libre d'ajouter des octets de remplissage de struct n'importe où entre les membres de struct / union, pour compenser le désalignement. Cela n'arrive pas dans ce cas précis, mais cela arriverait si nous l'utilisions par exemple
char c[3]. - Lorsque vous «tapez un jeu de mots» dans cette zone de mémoire en utilisant des courts-circuits, ils sont lus selon la finalité, car short est supérieur à 1 octet et est de type entier.
- Sur un processeur peu endian, vous obtiendrez donc chaque court pour supposer que 0xC est l'octet le moins significatif et donc le premier court se termine en
010Chexadécimal.
Si nous traduisons votre code en hexadécimal, cela devrait être plus clair:
#include <stdio.h>
int main()
{
union{
struct{
char c[2];
char ch[2];
}s;
struct {
short int i;
short int j;
}st;
}u={ {{0xC,0x1}, {0xF,0x1}} };
printf("%.4X\n%.4X",u.st.i,u.st.j);
}
Sortie sur CPU little endian:
010C
010F
10Ch = 268d et ainsi de suite.