OVH Cloud OVH Cloud

Taille de classe

32 réponses
Avatar
Lucas Levrel
Bonjour,

Si une classe A contient un champ de type T, est-il garanti que sizeof(A)
sera un multiple entier de sizeof(T) ?

Par exemple, si je définis
class A {
int un;
double deux;
}
(ou double d'abord et int ensuite) et que je compile avec le compilateur
Intel, j'obtiens sizeof(A)==16 (sachant que sizeof(int)==4 et
sizeof(double)==8). Est-ce imposé par la norme ? Est-ce un comportement
général des compilateurs courants ?

--
LL

10 réponses

1 2 3 4
Avatar
Lucas Levrel
Le 8 octobre 2012, Jean-Marc Bourguet a écrit :

Je suppose que sa fonction prend un déplacement et un pointeur vers
double. Lui faire comprendre qu'elle peut avoir des A nécessiterait soit de
la dupliquer pour tous les types possibles, soit en faire un template de
fonctions (ce est qui la meilleure solution en C++ pour l'interface, quite
à ce que l'implémentation du template fasse suivre à une fonction partagée
entre les instances si la duplication est réellement un problème).



Je ne sais pas faire tout ça (en gros, je fais du C with classes). Je
précise que je n'ai aucun contrôle sur la fonction : BLAS, ou Vector Math
Library d'Intel.

Il me semble que ça a été dit, il n'est en rien garanti que sizeof(A) soit
un multiple entier de sizeof(double). (Un int de 4 bytes et un double
aligné sur 4 bytes ne me semble pas une absurdité, en fait je serais même
surpris qu'aucun compilateur n'ait jamais utilisé ce mode).



Comme Olivier, je n'avais pas compris ça, et effectivement je n'avais pas
envisagé qu'un type simple ne soit pas aligné sur sa taille.

Ceci dit, je n'ai pas besoin de portabilité sur des architectures
anciennes. Mais je reconnais qu'on ne sait pas de quoi demain sera fait.

--
LL
Avatar
Lucas Levrel
Le 8 octobre 2012, Alain Ketterlin a écrit :

C'est cela qu'il faut faire, à mon avis. Des templates pour chaque cas,
spécialisés sur le type (A ici). C'est tellement petit ces calculs
d'adresse (et constant) que le compilo va inliner tout ça. Et s'il
n'inline pas, ça veut dire qu'on ne veut pas optimiser, et donc autant
avoir quelque chose de type-safe.



Bizarrement, j'ai des fonctions membres d'une ligne (avec un seul
point-virgule et pas de boucle ;-) ) qui ne sont pas inline-ées si je ne
les déclare pas inline. Du type :

void A::set_toto(A *ptr){toto=ptr;}

(où toto est un membre d'A, de type A*). Pourtant je compile avec -O3.

--
LL
Avatar
Lucas Levrel
(moi)>>> ptr += sizeof(A)/sizeof(double);

Le 08/10/2012 15:25, Jean-Marc Bourguet a écrit :
Tant qu'à jouer à bas niveau, j'aurais tendance à faire

ptr = (double*)(((char*)ptr) + sizeof(A));





Le 8 octobre 2012, Olivier Miakinen a écrit :
Oui. C'est un chouia plus lisible... ou du moins c'est plus courant.



C'est sans doute plus courant, mais je trouve ça moins lisible ; on passe
par un type qui n'apparaît pas explicitement dans le problème. Quand je
déclare un double*, je sais qu'il sera incrémenté par pas de
sizeof(double). Il me paraît donc naturel de demander
sizeof(A)/sizeof(double) pas. Mais pour ça je dois m'assurer de la
divisibilité bien sûr, d'où ce fil...

--
LL
Avatar
Alain Ketterlin
Lucas Levrel writes:

Le 8 octobre 2012, Alain Ketterlin a écrit :

C'est cela qu'il faut faire, à mon avis. Des templates pour chaque cas,
spécialisés sur le type (A ici). C'est tellement petit ces cal culs
d'adresse (et constant) que le compilo va inliner tout ça. Et s'il
n'inline pas, ça veut dire qu'on ne veut pas optimiser, et donc aut ant
avoir quelque chose de type-safe.



Bizarrement, j'ai des fonctions membres d'une ligne (avec un seul
point-virgule et pas de boucle ;-) ) qui ne sont pas inline-ées si je
ne les déclare pas inline. Du type :

void A::set_toto(A *ptr){toto=ptr;}

(où toto est un membre d'A, de type A*). Pourtant je compile avec -O 3.



Jamais vu ce genre de cas en -O3 avec gcc. Assure-toi que le code est
visible là ou elles sont appelées (sinon, pas d'inline évide mment),
qu'elle ne sont pas virtual, etc.

-- Alain.
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
Olivier Miakinen <om+ writes:

Le 08/10/2012 16:58, Alain Ketterlin a écrit :

Il me semble que ça a été dit, il n'est en rien garanti que






sizeof(A) soit
un multiple entier de sizeof(double). (Un int de 4 bytes et un double
aligné sur 4 bytes ne me semble pas une absurdité, en fait je serais même
surpris qu'aucun compilateur n'ait jamais utilisé ce mode).



Ce qu'on a dit, c'est que sizeof(A) est un multiple entier du plus grand
des champs (parce que celui-ci doit être aligné, y compris dans un
tableau). Et le plus grand a l'air d'être un double.



Un multiple entier du plus grand des champs, ou un multiple entier du
plus grand des alignements requis ?



Multiple entier du ppcm des alignements. (En pratique, je n'ai jamais vu
de contraintes d'alignement qui ne soit pas des puissances de 2, meme si
je suis a peu pres sur d'avoir vu une telle contrainte proposee pour les
instructions, en pratique donc multiple entier du plus grand des
alignements).



Tu as des contraintes d'alignement de pile et de trame pour les instructions
sse qui combinees ensemble te donnent des valeurs de type = 8 (module 16)...
Avatar
Lucas Levrel
Le 9 octobre 2012, Alain Ketterlin a écrit :

Jamais vu ce genre de cas en -O3 avec gcc. Assure-toi que le code est
visible là ou elles sont appelées (sinon, pas d'inline évidemment),
qu'elle ne sont pas virtual, etc.



Les one-liners sont définies dans le même fichier que toutes les fonctions
qui y font appel. Ces fonctions, elles, sont appelées dans différents
fichiers. Je compile avec icc.

--
LL
Avatar
Alain Ketterlin
Lucas Levrel writes:

Le 9 octobre 2012, Alain Ketterlin a écrit :

Jamais vu ce genre de cas en -O3 avec gcc. Assure-toi que le code est
visible là ou elles sont appelées (sinon, pas d'inline év idemment),
qu'elle ne sont pas virtual, etc.



Les one-liners sont définies dans le même fichier que toutes les
fonctions qui y font appel.



Si le code n'est pas dans la déclaration de la classe, alors elles
doivent être présentes dans le code produit. Ce qui ne veut pas d ire que
les appels locaux ne sont pas inlinées (comme pour n'importe quelle
fonction).

Il y a une raison pour les cacher comme ça ?

Ces fonctions, elles, sont appelées dans différents fichiers. Je
compile avec icc.



J'ai pas d'icc pour tester, mais à mon avis c'est un bug (missed
optimization opportunity). Pour un exemple comme celui que tu as montré
c'est vraiment bête, pour tout un tas de raisons (les sous-expressions,
l'aliasing, le scheduling, etc.)

-- Alain.
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

In article ,
Jean-Marc Bourguet wrote:
Olivier Miakinen <om+ writes:

Le 08/10/2012 16:58, Alain Ketterlin a écrit :

Il me semble que ça a été dit, il n'est en rien garant i que






sizeof(A) soit
un multiple entier de sizeof(double). (Un int de 4 bytes et un double
aligné sur 4 bytes ne me semble pas une absurdité, en fait je serais même
surpris qu'aucun compilateur n'ait jamais utilisé ce mode).



Ce qu'on a dit, c'est que sizeof(A) est un multiple entier du plus gra nd
des champs (parce que celui-ci doit être aligné, y compris d ans un
tableau). Et le plus grand a l'air d'être un double.



Un multiple entier du plus grand des champs, ou un multiple entier du
plus grand des alignements requis ?



Multiple entier du ppcm des alignements. (En pratique, je n'ai jamais vu
de contraintes d'alignement qui ne soit pas des puissances de 2, meme si
je suis a peu pres sur d'avoir vu une telle contrainte proposee pour les
instructions, en pratique donc multiple entier du plus grand des
alignements).



Tu as des contraintes d'alignement de pile et de trame pour les instructi ons
sse qui combinees ensemble te donnent des valeurs de type = 8 (module 1 6)...



Interessant. J'ai pas le temps de regarder pour confirmer, mais il me
semble qu'on sort du cadre de ce qui est exprimable comme contrainte
d'alignement en C11 et C++11. (En passant, je me demande d'ailleurs si
ces normes ne contraignent pas l'alignement a etre des puissances de 2,
il faudra que je regarde).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
Interessant. J'ai pas le temps de regarder pour confirmer, mais il me
semble qu'on sort du cadre de ce qui est exprimable comme contrainte
d'alignement en C11 et C++11. (En passant, je me demande d'ailleurs si
ces normes ne contraignent pas l'alignement a etre des puissances de 2,
il faudra que je regarde).



Je te rassure, mais le vieux code de pthread (et le code noyau de gestion
de threads) qui gerait ca cree de toutes facons ses piles a la main, en
assembleur.

Meme aujourd'hui, surtout en presence d'optimiseurs agressifs comme gcc.

Typiquement, il y a quelques options pour respecter ce genre de souci
d'ABI dans ton compilo... parce que typiquement, l'alignement de ta pile
est susceptible de changer selon les instructions que tu veux utiliser,
et parfois tu peux te retrouver a devoir reforcer le bon alignement de
pile en entree d'une fonction qui fait du sse, sachant que tu viens
de trucs plus "packes" que le reste.

Ca a toujours ete comme ca, et meme si C++ gere de plus en plus de
trucs bas niveau, les choses continuent quand meme d'evoluer.

(et je crois qu'on a des archis sur lesquelles on peut faire du multi-thread,
mais ou le modele de C++2011 d'atomics ne mappe pas correctement sur l'archi).
Avatar
ptyxs
Le 05/10/2012 21:38, Benoit Izac a écrit :
Quel est l'intérêt d'utiliser une classe sans méthode plutôt qu 'une
structure ?




En C+++ une structure et une classe c'est exactement la même chose.
C'est une simple convention fréquente mais en rien obligatoire d'appele r
plutôt structure les classes qui ne possèdent que des données publi ques.
1 2 3 4