2013-07-23 3 views
3

Je joue avec l'option du compilateur fdump-class-hierarchy mais je ne sais pas comment je peux comprendre la sortie. Que signifient "taille", "aligner", "taille de base" et "alignement de base", et comment sont-ils comptés? Merci!Comment puis-je comprendre la sortie fdump-class-hierarchy

Lorsque le code est:

class A 
{ 
public: 

private: 
    double m_nothing; 
    int m_number; 
}; 

La sortie est:

Class A 
    size=16 align=8 
    base size=16 base align=8 
A (0x406c690) 0 

Mais, si je change la classe un peu:

class A 
{ 
public: 

private: 
    int m_number; 
    double m_nothing; 
}; 

la sortie sera:

Class A 
    size=16 align=8 
    base size=12 base align=8 
A (0x406c690) 0 
+3

Je pense que vous avez oublié de changer un peu la classe. – chris

+0

Ohh désolé! Dans le deuxième exemple, j'ai échangé la variable de deux membres. – user19840919

Répondre

8

Les dimensions size et align représentent la taille et l'alignement de la classe lorsqu'elle est utilisée en tant que type complet. C'est-à-dire, si vous créez des objets dont le type complet est ce type (comme définir des variables de ce type, ou utiliser ce type avec new).

La taille est simplement le nombre d'octets qu'elle occupe. Donc size=16 signifie lorsqu'il est utilisé en tant que type complet, il occupe toujours 16 octets.

L'alignement vous indique où l'objet peut être placé: align=8 signifie que l'adresse de l'objet doit être un multiple entier de 8.

Le base size et base align donner la taille et l'alignement dans le cas où la classe est utilisée comme classe de base. La raison pour laquelle ils sont différents est que la norme C++ permet aux objets d'utiliser moins de remplissage lorsqu'ils sont utilisés en tant que classe de base. Alors regardons spécifiquement votre exemple (je suppose que vous avez réellement le int devant le double dans le premier cas). J'omets également le public et private parce qu'ici ils ne changent rien (si vous aviez des membres de données publics ou privés, pourrait en principe changer quelque chose, mais je ne sais pas si n'importe quel compilateur en profite). Je devine également la taille et l'alignement de int et double (en fait les valeurs que je suppose sont un choix assez commun, et expliquent les valeurs que vous obtenez).

Ainsi, dans le premier cas (je suppose) que vous avez

class A 
{ 
    int m_number; 
    double m_nothing; 
}; 

Maintenant int a la taille et l'alignement 4 et double a la taille et l'alignement 8. Alors, faisons le travail du compilateur et construisons notre classe. D'abord, nous avons m_number, qui occupe 4 octets. Nous devons mettre les membres dans l'ordre donné, si m_number va au début de A:

iiii 

Jusqu'à présent, nous avons la taille 4 (quatre octets pour l'int) et l'alignement 4 (car int a l'alignement 4). Mais maintenant nous devons ajouter un double (taille et alignement 8).Puisque directement après l'int, nous sommes à l'adresse (relative) 4, nous ne sommes pas correctement alignés pour le double, donc nous devons ajouter 4 padding octets (que je marquerai avec *) pour obtenir un multiple de 8 Nous obtenons ainsi pour notre classe:

iiii****dddddddd 

Maintenant, si la classe est utilisée comme classe de base, nous avons terminé. Ainsi, nous avons base size=16 et base align=8 (nous avons besoin d'un alignement de 8 pour obtenir le double alignement correctement).

Pour l'objet complet, il y a une autre considération: La norme exige que dans les tableaux, les objets se suivent sans espace entre les deux. C'est-à-dire que le premier octet après l'objet doit être correctement aligné pour l'objet suivant. Ce qui signifie finalement que la taille de l'objet complet doit être un multiple de son alignement.

Maintenant, la disposition des objets que nous avons trouvée répond déjà à cette exigence. Par conséquent, nous pouvons l'utiliser également pour l'objet complet. Par conséquent, nous obtenons size=16 et align=8 pour l'objet complet.

Considérons maintenant le cas où l'ordre est inversé:

class A 
{ 
    double m_nothing; 
    int m_number; 
}; 

Maintenant, nous devons commencer par le double:

dddddddd 

Ensuite, nous devons ajouter le int. Comme il se trouve, la place à côté libre est déjà aligné correctement pour un int, on peut donc tout simplement l'ajouter:

ddddddddiiii 

Maintenant, pour l'utilisation comme objet de base, nous sommes prêts. Comme vous pouvez le voir, nous n'avions besoin que de 12 octets, donc base size=12. Bien sûr, pour que le double soit correctement aligné, l'objet doit à nouveau commencer à une adresse qui est un multiple de 8. Nous avons donc base align=8.

Cependant, pour le poursuivre en justice comme objet complet, nous constatons maintenant que l'adresse suivante serait en position 12, qui est pas correctement aligné pour le membre double. Par conséquent, nous devons ajouter des octets de remplissage jusqu'à atteindre une adresse alignée correctement à nouveau: Comme vous pouvez le voir

ddddddddiiii**** 

, maintenant nous avons besoin de 16 octets, size=16 ainsi. Nous avons encore align=8 en raison du double. Notez que l'exigence d'alignement peut affecter considérablement la taille d'une classe. Considérons par exemple les deux types suivants:

struct S1 
{ 
    char c1; 
    double d1; 
    char c2; 
    double d2; 
    char c3; 
}; 

struct S2 
{ 
    double d1; 
    double d2; 
    char c1; 
    char c2; 
    char c3; 
}; 

Bien que les deux contiennent les mêmes membres, S1 seront les tailles et les alignements ci-dessus ont une taille totale (non-base) de 40, alors que la taille totale de S2 sera juste 24.En effet, les objets de type S1 seront, comme objet complet, regardez comme

c*******ddddddddc*******ddddddddc******* 

tandis que ceux de type S2 ressemblera

ddddddddddddddddccc***** 

Ainsi, la ligne de fond est que les membres avec l'exigence d'alignement le plus élevé devrait toujours venir en premier.

Notez également que sizeof renvoie la taille des objets complets, c'est-à-dire que le vidage de la hiérarchie de classes appelle size.

+0

Bonne réponse. Il me semble que l'on obtient des classes plus petites si l'on déclare toujours les plus grands membres en premier. Ai-je raison? –

+0

Ce n'est pas la taille, mais l'alignement qui est pertinent ici. Par exemple, 'struct X {char s [17]; } 'est plus grand que' double', mais a un alignement 1 (et une taille qui n'est pas un multiple de l'alignement du double). Une structure contenant 'X' suivie de' double' suivie de 'char' serait plus grande (plus de remplissage) que si le double venait en premier. – celtschk