2017-02-28 1 views
0

Considérons un MWE:paniers structures tailles et héritage avec différents compilateurs

#include <iostream> 

struct A  {}   __attribute__((packed)) ; 
struct B : A { int x; } __attribute__((packed)) ; 

struct C : A { B y; } __attribute__((packed)) ; 

int main() { 
    std::cout << "Size of A: " << sizeof(A) << std::endl; 
    std::cout << "Size of B: " << sizeof(B) << std::endl; 
    std::cout << "Size of C: " << sizeof(C) << std::endl; 
}; 

Sur Linux j'ai essayé de le compiler et exécuter:

$ g++ --version 
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 

$ g++ ./test.cpp && ./a.out 
Size of A: 1 
Size of B: 4 
Size of C: 5 

Quant à A et B tout est clair. Mais qu'en est-il de C? Qu'est-ce qui ajoute 1 octet à la taille de C? De plus, si vous supprimez des relations d'héritage, que ce soit pour B ou C, C devient de taille 4. En utilisant des compilateurs MS (au moins un qui est livré avec VS 2013), j'ai obtenu 1, 4 et 4 tailles. Toute explication et les détails à ce sujet sont appréciés.

+1

Possible copie de [Pourquoi la taille d'une structure empaquetée serait-elle différente sur Linux et Windows lors de l'utilisation de gcc?] (Http://stackoverflow.com/questions/7789668/why-would-the-size-of-a -packed-structure-être-différent-sur-linux-et-windows-quand) – MSD

+0

@saranyadeviM, j'ai vu cette question. À mon avis, il discute des raisons pour lesquelles les structures peuvent être emballées de différentes manières en général (!). Je m'intéresse plus à la façon dont l'héritage affecte les résultats de l'empaquetage et comment exactement l'héritage mélangé avec la composition ajoute 1 octet à la taille d'une structure. Donc, je crois que ma question est plus spécifique. :) – CaptainTrunky

Répondre

2

[class.derived]/7 (projet de norme)

... Une classe de base sous-objet peut être de taille zéro (Clause [classe]); cependant, deux sous-objets ayant le même type de classe et appartenant au même objet le plus dérivé ne doivent pas être alloués à la même adresse ([expr.eq]). - Note d'extrémité]

C a sous-objets B::A (base de l'élément y) et C::A (base directe) qui sont tous deux de type A. y pourrait autrement être à la même adresse que la base vide de C, mais puisqu'il a également une base de même type, cette base de B peut ne pas avoir la même adresse et doit donc être décalée avec un remplissage. GCC suit cette règle et applique uniquement la demande d'emballage au remplissage qui était nécessaire pour un alignement correct.

+0

Cela semble raisonnable. Cela répond à ma question initiale, mais en soulève une autre: est-il possible de casser quelque chose quand cette hypothèse ne tient pas? La seule chose qui vient à l'esprit est d'utiliser des pointeurs comme des clés pour quelque chose. Dans ce cas, ils doivent être différents. Mais c'est plutôt une chose exotique à faire. – CaptainTrunky

+0

@CaptainTrunky Bonne question. Je pense que tout code qui en dépend doit être assez compliqué, mais ce n'est peut-être qu'un manque d'imagination. En effet, quelque chose qui traite de l'identité des objets, comme l'utilisation de pointeurs comme clés peut être affecté. – user2079303