24 votes

sizeof une union en C/C++

Qu'est-ce que le sizeof l'union en C/C++? Est-ce la sizeof le plus grand type de données à l'intérieur? Si oui, comment le compilateur calculer comment faire pour déplacer le pointeur de pile, si l'un des plus petits de type de données de l'union est active?

37voto

Mehrdad Afshari Points 204872

Un union prend toujours moins d'espace que les membres les plus importants. Il n'a pas d'importance ce qui est actuellement en cours d'utilisation.

union {
  short x;
  int y;
  long long z;
}

Une instance de ce qui précède union y en aura toujours au moins un long long pour le stockage.

Remarque: Comme indiqué par Stefano, l'espace réel n'importe quel type (union, struct, class) prendra repose sur d'autres questions telles que l'alignement par le compilateur. Je n'ai pas aller par le biais de ce pour des raisons de simplicité que je voulais juste dire qu'un syndicat prend le plus grand élément en compte. Il est important de savoir que la taille réelle ne dépend de l'alignement.

19voto

Johannes Schaub - litb Points 256113

Le Standard répond à toutes les questions dans la section 9.5:

Dans un syndicat, au plus l'un des membres de données peut être actif à tout moment, c'est la valeur d'au plus un des membres de données peuvent être stockées dans une union à tout moment. [Note: une garantie spéciale est faite dans le but de simplifier l'utilisation des syndicats: Si un POD-union contient plusieurs GOUSSES aux structures qui partagent une même séquence initiale (9.2), et si un objet de ce POD-union type contient l'un des GOUSSES de structures, il est autorisé à inspecter la commune de la séquence initiale de tout de POD-les membres de la structure; voir 9.2. ] La taille d'une union est suffisant pour contenir la plus grande de ses membres de données. Chaque membre de données est répartie comme si elle était le seul membre d'une struct.

Cela signifie que chaque membre partagent la même mémoire de la région. Il est tout au plus un membre actif, mais vous ne pouvez pas trouver celui qui. Vous aurez à stocker de l'information à propos de la actuellement membre actif vous-même quelque part d'autre. Stockage tel un drapeau en plus de l'union (par exemple avoir une structure avec un entier comme le type d'un drapeau et d'une union que les données de la boutique) vous donnera une sorte de "discrimination de l'union": Une union qui sait quel type il est actuellement le "actif".

L'utilisation la plus courante est dans lexers, où vous pouvez avoir des jetons différents, mais selon le jeton, vous avez différentes informations à stocker (mettre line dans chaque structure pour montrer ce qu'est une commune de la séquence initiale est):

struct tokeni {
    int token; /* type tag */
    union {
        struct { int line; } noVal;
        struct { int line; int val; } intVal;
        struct { int line; struct string val; } stringVal;
    } data;
};

Le Standard vous permet d'accéder line de chaque membre, parce que c'est la commune de la séquence initiale de chacun.

Il n'existe pas de compilateur extensions qui permettent l'accès à tous les membres de mépris dont on dispose actuellement de sa valeur stockée. Qui permet efficace réinterprétation de bits stockés avec différents types entre chacun des membres. Par exemple, les éléments suivants peuvent être utilisés pour la dissection d'une variable de type float en 2 unsigned short:

union float_cast { unsigned short s[2]; float f; };

Que peut venir ce qui est très pratique lors de l'écriture d'au code de bas niveau. Si le compilateur ne prend pas en charge cette extension, mais vous le faites quand même, vous écrivez du code, dont les résultats ne sont pas définis. Alors, soyez certain que votre compilateur a le support si vous utilisez cette astuce.

14voto

Stefano Borini Points 36904

Il dépend du compilateur et les options.

int main() {
  union {
    char all[13];
    int foo;
  } record;

printf("%d\n",sizeof(record.all));
printf("%d\n",sizeof(record.foo));
printf("%d\n",sizeof(record));

}

Ce sorties:

13 4 16

Si je me souviens bien, cela dépend de l'alignement que le compilateur met dans l'espace alloué. Donc, sauf si vous utilisez une option spéciale, le compilateur va mettre du rembourrage dans votre union de l'espace.

edit: avec gcc, vous devez utiliser une directive pragma

int main() {
#pragma pack(push, 1)
      union {
           char all[13];
           int foo;
      } record;
#pragma pack(pop)

      printf("%d\n",sizeof(record.all));
      printf("%d\n",sizeof(record.foo));
      printf("%d\n",sizeof(record));

}

ce sorties

13 4 13

Vous pouvez également le voir à partir de la démonter (supprimé certains printf, pour plus de clarté)

  0x00001fd2 <main+0>:    push   %ebp             |  0x00001fd2 <main+0>:    push   %ebp
  0x00001fd3 <main+1>:    mov    %esp,%ebp        |  0x00001fd3 <main+1>:    mov    %esp,%ebp
  0x00001fd5 <main+3>:    push   %ebx             |  0x00001fd5 <main+3>:    push   %ebx
  0x00001fd6 <main+4>:    sub    $0x24,%esp       |  0x00001fd6 <main+4>:    sub    $0x24,%esp
  0x00001fd9 <main+7>:    call   0x1fde <main+12> |  0x00001fd9 <main+7>:    call   0x1fde <main+12>
  0x00001fde <main+12>:   pop    %ebx             |  0x00001fde <main+12>:   pop    %ebx
  0x00001fdf <main+13>:   movl   $0xd,0x4(%esp)   |  0x00001fdf <main+13>:   movl   $0x10,0x4(%esp)                                         
  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax  |  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax
  0x00001fed <main+27>:   mov    %eax,(%esp)      |  0x00001fed <main+27>:   mov    %eax,(%esp)
  0x00001ff0 <main+30>:   call  0x3005 <printf>   |  0x00001ff0 <main+30>:   call   0x3005 <printf>
  0x00001ff5 <main+35>:   add    $0x24,%esp       |  0x00001ff5 <main+35>:   add    $0x24,%esp
  0x00001ff8 <main+38>:   pop    %ebx             |  0x00001ff8 <main+38>:   pop    %ebx
  0x00001ff9 <main+39>:   leave                   |  0x00001ff9 <main+39>:   leave
  0x00001ffa <main+40>:   ret                     |  0x00001ffa <main+40>:   ret

Où la seule différence est dans la principale+13), où le compilateur alloue sur la pile 0xd au lieu de 0x10

11voto

mouviciel Points 36624

Il n'y a pas de notion de type de données active pour une union. Vous êtes libre de lire et d'écrire n'importe "membre" de l'union: c'est à vous d'interpréter ce que vous obtenez.

Par conséquent, la sizeof un syndicat est toujours la sizeof son plus grand type de données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X