Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Taille de classe

60 views
Skip to first unread message

Lucas Levrel

unread,
Oct 4, 2012, 6:53:47 AM10/4/12
to
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

Alain Ketterlin

unread,
Oct 4, 2012, 7:42:02 AM10/4/12
to
Lucas Levrel <lucas....@u-pec.fr> writes:

> 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 ?

Si mes souvenirs sont bons, la règle est que les champs soient alignés
sur un multiple de leur taille. Dans ton exemple, il y a donc un padding
entre un et deux, pour que le double soit aligné sur un multiple de 8.
Si tu changes l'ordre, tu devrais arriver à 12.

-- Alain.

Lucas Levrel

unread,
Oct 4, 2012, 7:58:40 AM10/4/12
to
Le 4 octobre 2012, Alain Ketterlin a ᅵcrit :

> Si mes souvenirs sont bons, la rᅵgle est que les champs soient alignᅵs
> sur un multiple de leur taille. Dans ton exemple, il y a donc un padding
> entre un et deux, pour que le double soit alignᅵ sur un multiple de 8.
> Si tu changes l'ordre, tu devrais arriver ᅵ 12.

Merci. J'obtiens 16 quel que soit l'ordre : peut-ᅵtre parce qu'il faut
pouvoir faire des vecteurs dont chaque ᅵlᅵment est alignᅵ ?

--
LL

Jean-Marc Bourguet

unread,
Oct 4, 2012, 8:54:06 AM10/4/12
to
Lucas Levrel <lucas....@u-pec.fr> writes:

> Le 4 octobre 2012, Alain Ketterlin a écrit :
>
>> Si mes souvenirs sont bons, la règle est que les champs soient alignés
>> sur un multiple de leur taille. Dans ton exemple, il y a donc un padding
>> entre un et deux, pour que le double soit aligné sur un multiple de 8.
>> Si tu changes l'ordre, tu devrais arriver à 12.
>
> Merci. J'obtiens 16 quel que soit l'ordre : peut-être parce qu'il faut
> pouvoir faire des vecteurs dont chaque élément est aligné ?

Oui. Une struct est au moins autant alignee que le plus aligne de ses
membres.

(Il y a des machines ou ne pas respecter l'alignement cause des crashs,
d'autres ou ce n'est qu'un probleme potentiel -- il peut y avoir
d'autres conditions -- de perf).

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

Lucas Levrel

unread,
Oct 4, 2012, 10:42:51 AM10/4/12
to
Le 4 octobre 2012, Jean-Marc Bourguet a ᅵcrit :

> Oui. Une struct est au moins autant alignee que le plus aligne de ses
> membres.

Merci !

--
LL

Marc Boyer

unread,
Oct 5, 2012, 4:25:11 AM10/5/12
to
Le 04-10-2012, Lucas Levrel <lucas....@u-pec.fr> a écrit :
> 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 ?

J'ai pas la norme en tête, mais les compilos ont deux contraintes:
1) respecter l'ordre des champs dans la déclaration
2) respecter des contraintes d'alignement, qui permettent de faire des
tableaux contigus

Donc, on va avoir un A aligné sur le plus contraint de ses membres
(sachant que si on a des fonctions virtuelles, le compilo va surement
ajouter un pointeur quelque part dans A).

Mais alignement et taille sont distincts:
#include <iostream>

class A {
public:
char x[5];
char y[3];
};

int main(){
std::cout<<sizeof(A::x)<<std::endl;
std::cout<<sizeof(A::y)<<std::endl;;
std::cout<<sizeof(A)<<std::endl;;
}

Avec mon g++, j'ai 5, 3 et 8. Et 8 n'est ni multiple de 5 ou 3.

Marc Boyer
--
À mesure que les inégalités regressent, les attentes se renforcent.
François Dubet

Lucas Levrel

unread,
Oct 5, 2012, 9:31:16 AM10/5/12
to
Le 5 octobre 2012, Marc Boyer a écrit :

> #include <iostream>
>
> class A {
> public:
> char x[5];
> char y[3];
> };
>
> int main(){
> std::cout<<sizeof(A::x)<<std::endl;
> std::cout<<sizeof(A::y)<<std::endl;;
> std::cout<<sizeof(A)<<std::endl;;
> }
>
> Avec mon g++, j'ai 5, 3 et 8. Et 8 n'est ni multiple de 5 ou 3.

Ah oui, je n'avais pas pensé aux types tableaux (qui reviennent à
multiplier le type de base). Dans mon cas j'ai effectivement des tableaux
dans la classe, « cachés » par un typedef qui plus est, mais heureusement
je n'ai besoin que de la multiplicité par rapport au type de base.

--
LL

Benoit Izac

unread,
Oct 5, 2012, 3:38:33 PM10/5/12
to
Bonjour,

le 04/10/2012 à 12:53, Lucas Levrel a écrit dans le message
<alpine.LNX.2.00.1...@coulomb.univ-paris12.fr> :

> 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 ?

Quel est l'intérêt de connaître la taille d'une classe ?
Quel est l'intérêt d'utiliser une classe sans méthode plutôt qu'une
structure ?

--
Benoit Izac

Alain Ketterlin

unread,
Oct 5, 2012, 4:08:00 PM10/5/12
to
Benoit Izac <use.re...@INVALID.ADDRESS> writes:

> le 04/10/2012 à 12:53, Lucas Levrel a écrit dans le message
> <alpine.LNX.2.00.1...@coulomb.univ-paris12.fr> :
>
>> 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 ?
>
> Quel est l'intérêt de connaître la taille d'une classe ?

Tu veux sûrement dire la taille des instances ? Je ne pense pas que ce
soit la taille en soi qui intéresse Lucas, mais plutôt la fragmentation
induite par l'ordre et l'alignement des champs. Celui qui écrit :

struct s {
int x
double y;
int z;
};

paye 24 octets pour 16 utiles (sur une configuration fréquente). Cela
peut vite s'accumuler si tu imbriques beaucoup. Par exemple, pour

struct t {
s s1;
s s2;
};

mon g++ 4.6.3 m'annonce 48 octets. Et si tu as beaucoup d'objets (dans
des tableaux/vecteurs par exemple), cela peut commencer à chiffrer. Ca
remplit la mémoire, les caches, etc.

> Quel est l'intérêt d'utiliser une classe sans méthode plutôt qu'une
> structure ?

Fournir un exemple minimal qui illustre son propos, j'imagine. Rien
d'autre, pas de panique, ce n'est manifestement pas du code de
production, de toute façon il manque le point-virgule.

-- Alain.

Benoit Izac

unread,
Oct 5, 2012, 4:34:06 PM10/5/12
to
Bonjour,

le 05/10/2012 � 22:08, Alain Ketterlin a �crit dans le message
<87mx00f...@dpt-info.u-strasbg.fr> :

>> Quel est l'int�r�t de conna�tre la taille d'une classe ?
>
> Tu veux s�rement dire la taille des instances ?

L'exemple de Marc n'utilise pas d'instance.

> Je ne pense pas que ce soit la taille en soi qui int�resse Lucas, mais
> plut�t la fragmentation induite par l'ordre et l'alignement des
> champs. Celui qui �crit :
>
> struct s {
> int x
> double y;
> int z;
> };
>
> paye 24 octets pour 16 utiles (sur une configuration fr�quente). Cela
> peut vite s'accumuler si tu imbriques beaucoup. Par exemple, pour
>
> struct t {
> s s1;
> s s2;
> };
>
> mon g++ 4.6.3 m'annonce 48 octets. Et si tu as beaucoup d'objets (dans
> des tableaux/vecteurs par exemple), cela peut commencer � chiffrer. Ca
> remplit la m�moire, les caches, etc.

Je comprends le probl�me pour les structures (�a a �t� discut� dans fclc
il y a quelques temps). En revanche, ne connaissant pas C++, je me dis
qu'il doit y avoir une raison pour choisir un classe plut�t qu'une
structure.

� ce propos, � chaque fois qu'une instance est cr�e, est-ce que le code
des m�thodes est dupliqu� ?

>> Quel est l'int�r�t d'utiliser une classe sans m�thode plut�t qu'une
>> structure ?
>
> Fournir un exemple minimal qui illustre son propos, j'imagine. Rien
> d'autre, pas de panique, ce n'est manifestement pas du code de
> production, de toute fa�on il manque le point-virgule.

Je ne panique pas. ;-)

--
Benoit Izac

Alain Ketterlin

unread,
Oct 5, 2012, 4:45:55 PM10/5/12
to
Benoit Izac <use.re...@INVALID.ADDRESS> writes:

> le 05/10/2012 à 22:08, Alain Ketterlin a écrit dans le message
> <87mx00f...@dpt-info.u-strasbg.fr> :
>
>>> Quel est l'intérêt de connaître la taille d'une classe ?
>>
>> Tu veux sûrement dire la taille des instances ?
>
> L'exemple de Marc n'utilise pas d'instance.

sizeof() renseigne sur la taille des instance.

[...]
> À ce propos, à chaque fois qu'une instance est crée, est-ce que le code
> des méthodes est dupliqué ?

Non non, le code est là une fois pour toute.

-- Alain.

Marc Espie

unread,
Oct 5, 2012, 5:00:22 PM10/5/12
to
In article <87haq8l...@izac.org>, Benoit Izac <benoi...@free.fr> wrote:
>Je comprends le probl�me pour les structures (�a a �t� discut� dans fclc
>il y a quelques temps). En revanche, ne connaissant pas C++, je me dis
>qu'il doit y avoir une raison pour choisir un classe plut�t qu'une
>structure.

Benoit, je t'aime bien, mais dans ce cas-la precise que tu es un gros
debutant, ca evitera de rajouter du bruit...

Alors, voila. class et struct, pour des definitions de structure, c'est
la meme chose en C++. Le seul point qui change, c'est la visibilite
par defaut des membres de l'agregat (avec class, ils sont private. Avec
struct, ils sont publics).

Cote layout memoire, c'est comme du C, dans la mesure ou ca a un sens!
Il y a une description assez simple dans la norme C++98, et un peu
plus complexe (nettement) dans la norme C++2011.

En simplifiant, l'esprit c'est que tu n'es pas cense payer plus cher en
C++ qu'en C. Du coup, s'il n'y a pas de fonctionnalite supplementaire
du C++, qui necessite une vtable, une structure C++ va faire exactement
la meme taille que la structure equivalente C, et avoir le meme layout.

Si ta classe n'a que des champs fonction non polymorphes (rien de virtual),
alors elle n'a rien besoin de stocker pour ceux-ci. Des qu'il y a du
polymorphisme (virtual), il faut des infos cachees pour retrouver les
methodes. Traditionnellement, vtable... ca se complique en presence
d'heritage, avec plein, plein d'optimisations sophistiquees sur les
implementations recentes.

Dans la nouvelle norme, on detaille en plus le processus de construction
des instances, sachant qu'une struct "sans rien" se construit et se copie
a la main, mais que ca se complique des qu'il y a constructeurs ou destructeurs.

Plus exactement, la nouvelle norme explique plus en detail:
- les cas ou le layout d'une instance C++ est le meme que pour la struct C
equivalente.
- les cas ou on peut joyeusement copier des objets d'un endroit a l'autre
bit-a-bit, a la meme copie.

Une 'chtite particularite du C++, c'est la tres fameuse
"Empty base optimisation".

Comme en C, une struct, meme vide, DOIT faire au moins un octet.

Du coup, si on fait des trucs composites, genre:

struct A {};

struct B {
A a;
...
};

alors le champs a doit occuper au moins un octet.

Alors que si on fait pareil en heritant:
struct Bp: public A {
...
};

ben la classe de base A peut totalement etre optimisee.

(evidemment, une struct sans rien ne sert a rien... ca va etre utile uniquement
pour recuperer les fonctions membres qui vont avec).


Voila pour un petit resume sommaire des differences saillantes avec C
cote disposition memoire.

Benoit Izac

unread,
Oct 6, 2012, 3:06:54 AM10/6/12
to
Bonjour,

le 05/10/2012 à 23:00, Marc Espie a écrit dans le message
<k4nhp6$2mh0$1...@saria.nerim.net> :

>>Je comprends le problème pour les structures (ça a été discuté dans fclc
>>il y a quelques temps). En revanche, ne connaissant pas C++, je me dis
>>qu'il doit y avoir une raison pour choisir un classe plutôt qu'une
>>structure.
>
> Benoit, je t'aime bien, mais dans ce cas-la precise que tu es un gros
> debutant, ca evitera de rajouter du bruit...
>
> Alors, voila. [...]

Merci pour les explications bien que ma culture C++ ne me permette pas
d'en comprendre la totalité. Notamment pour les vtables, je n'ai pas
encore écris mon propre compilateur "from scratch". ;-)

--
Benoit Izac

Lucas Levrel

unread,
Oct 8, 2012, 5:06:43 AM10/8/12
to
Le 5 octobre 2012, Alain Ketterlin a ᅵcrit :

>>> class A {
>>> int un;
>>> double deux;
>>> }
>
> Tu veux sᅵrement dire la taille des instances ? Je ne pense pas que ce
> soit la taille en soi qui intᅵresse Lucas, mais plutᅵt la fragmentation
> induite par l'ordre et l'alignement des champs.

Les deux en fait. J'ai un tableau d'A :
A tab[1000];
et je veux en extraire un tableau d'A.deux. Donc je dᅵfinis
double *ptr=&(tab->deux);
puis je fais une boucle qui incrᅵmente
ptr += sizeof(A)/sizeof(double);

(Ou j'utilise une fonction de bibliothᅵque ᅵ laquelle je passe le
ᅵᅵstrideᅵᅵ sizeof(A)/sizeof(double).)

--
LL

Olivier Miakinen

unread,
Oct 8, 2012, 5:20:25 AM10/8/12
to
Bonjour,

Le 08/10/2012 11:06, Lucas Levrel a ᅵcrit :
>
>>>> class A {
>>>> int un;
>>>> double deux;
>>>> }
>
> J'ai un tableau d'A :
> A tab[1000];
> et je veux en extraire un tableau d'A.deux. Donc je dᅵfinis
> double *ptr=&(tab->deux);
> puis je fais une boucle qui incrᅵmente
> ptr += sizeof(A)/sizeof(double);

C'est un peu casse-gueule, tu ne crois pas ? Alors qu'il serait si
simple d'avoir un pointeur sur A, que tu incrᅵmentes normalement,
avant d'en extraire le deux ᅵ chaque tour de boucle.

Plus prᅵcisᅵment, je pense que ta technique doit fonctionner, peut-ᅵtre
mᅵme la norme te donnera-t-elle l'assurance que ᅵa fonctionnera partout
(ᅵ vᅵrifier tout de mᅵme), mais si toi ou quelqu'un d'autre se trouve
devoir dᅵbuguer ce code dans quelques mois ou quelques annᅵes ᅵa risque
d'ᅵtre difficile ᅵ relire.

Cordialement,
--
Olivier Miakinen

Jean-Marc Bourguet

unread,
Oct 8, 2012, 9:25:29 AM10/8/12
to
Olivier Miakinen <om+...@miakinen.net> writes:

> Bonjour,
>
> Le 08/10/2012 11:06, Lucas Levrel a �crit :
>>
>>>>> class A {
>>>>> int un;
>>>>> double deux;
>>>>> }
>>
>> J'ai un tableau d'A :
>> A tab[1000];
>> et je veux en extraire un tableau d'A.deux. Donc je d�finis
>> double *ptr=&(tab->deux);
>> puis je fais une boucle qui incr�mente
>> ptr += sizeof(A)/sizeof(double);

Tant qu'� jouer � bas niveau, j'aurais tendence � faire

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

au moins je ne vois pas de probl�mes (cast de et vers char* ne pose pas
de probl�me d'alias, ajouter sizeof(A) puis recaster en double* fonctionne
m�me si le ppcm de l'alignement d'un double et d'un int est plus petit que
la taille d'un double)

> C'est un peu casse-gueule, tu ne crois pas ? Alors qu'il serait si
> simple d'avoir un pointeur sur A, que tu incr�mentes normalement,
> avant d'en extraire le deux � chaque tour de boucle.

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).

> Plus pr�cis�ment, je pense que ta technique doit fonctionner, peut-�tre
> m�me la norme te donnera-t-elle l'assurance que �a fonctionnera partout
> (� v�rifier tout de m�me), mais si toi ou quelqu'un d'autre se trouve
> devoir d�buguer ce code dans quelques mois ou quelques ann�es �a risque
> d'�tre difficile � relire.

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).

A+

--
Jean-Marc
FAQ de fclc++: http://web.archive.org/web/*/http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ

Alain Ketterlin

unread,
Oct 8, 2012, 10:58:04 AM10/8/12
to
Jean-Marc Bourguet <j...@bourguet.org> writes:

>>>>>> class A {
>>>>>> int un;
>>>>>> double deux;
>>>>>> }
>>>
>>> J'ai un tableau d'A :
>>> A tab[1000];
>>> et je veux en extraire un tableau d'A.deux. Donc je définis
>>> double *ptr=&(tab->deux);
>>> puis je fais une boucle qui incrémente
>>> ptr += sizeof(A)/sizeof(double);

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

>> C'est un peu casse-gueule, tu ne crois pas ? Alors qu'il serait si
>> simple d'avoir un pointeur sur A, que tu incrémentes normalement,
>> avant d'en extraire le deux à chaque tour de boucle.
>
> 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).

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.

>> Plus précisément, je pense que ta technique doit fonctionner, peut-être
>> même la norme te donnera-t-elle l'assurance que ça fonctionnera partout
>> (à vérifier tout de même), mais si toi ou quelqu'un d'autre se trouve
>> devoir débuguer ce code dans quelques mois ou quelques années ça risque
>> d'être difficile à relire.
>
> 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. Je ne connais pas
d'archi ou sizeof(double) < sizeof(int), mais pourquoi pas...

-- Alain.

Olivier Miakinen

unread,
Oct 8, 2012, 12:12:29 PM10/8/12
to
Le 08/10/2012 15:25, Jean-Marc Bourguet a ᅵcrit :
>>>
>>>>>> class A {
>>>>>> int un;
>>>>>> double deux;
>>>>>> }
>>>
>>> J'ai un tableau d'A :
>>> A tab[1000];
>>> et je veux en extraire un tableau d'A.deux. Donc je dᅵfinis
>>> double *ptr=&(tab->deux);
>>> puis je fais une boucle qui incrᅵmente
>>> ptr += sizeof(A)/sizeof(double);
>
> Tant qu'ᅵ jouer ᅵ bas niveau, j'aurais tendance ᅵ faire
>
> ptr = (double*)(((char*)ptr) + sizeof(A));

Oui. C'est un chouia plus lisible... ou du moins c'est plus courant.

> au moins je ne vois pas de problᅵmes (cast de et vers char* ne pose pas
> de problᅵme d'alias, ajouter sizeof(A) puis recaster en double* fonctionne

Oui.

> mᅵme si le ppcm de l'alignement d'un double et d'un int est plus petit que
> la taille d'un double)

Parce qu'un double pourrait ᅵtre alignᅵ sur moins que sa taille ?
Par exemple il pourrait avoir une taille de 8 octets et ᅵtre alignᅵ
sur 4 ? Quoi qu'il en soit, si c'est le cas le calcul de ptr ci-dessus
donnera une adresse valide pour un pointeur vers double, donc je ne
vois pas non plus de problᅵme (sauf de lisibilitᅵ, quand mᅵme un petit
peu...)

>> C'est un peu casse-gueule, tu ne crois pas ? Alors qu'il serait si
>> simple d'avoir un pointeur sur A, que tu incrᅵmentes normalement,
>> avant d'en extraire le deux ᅵ chaque tour de boucle.
>
> Je suppose que sa fonction prend un dᅵplacement et un pointeur vers
> double.

Ok, je comprends.

> 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).

Ok.

>> Plus prᅵcisᅵment, je pense que ta technique doit fonctionner, peut-ᅵtre
>> mᅵme la norme te donnera-t-elle l'assurance que ᅵa fonctionnera partout
>> (ᅵ vᅵrifier tout de mᅵme), mais si toi ou quelqu'un d'autre se trouve
>> devoir dᅵbuguer ce code dans quelques mois ou quelques annᅵes ᅵa risque
>> d'ᅵtre difficile ᅵ relire.
>
> 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).

Je suis dᅵsolᅵ si je n'ai pas tout lu (ou pas tout compris) de ce qui
s'est dit prᅵcᅵdemment. Je dᅵcouvre qu'on pourrait avoir un type simple
donc la taille est plus grande que son alignement, chose que j'ignorais.

Cordialement,
--
Olivier Miakinen

Olivier Miakinen

unread,
Oct 8, 2012, 12:17:33 PM10/8/12
to
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 ?

> Je ne connais pas
> d'archi ou sizeof(double) < sizeof(int), mais pourquoi pas...

;-)

Pourquoi pas, en effet, mais ce n'est pas lᅵ que serait le problᅵme.

Il y aurait problᅵme si on avait sizeof(int) = 4, sizeof(double) = 8,
mais alignement(int) = alignement(double) = 4. Dans ce cas, la taille
de A serait de 12 octets, et sizeof(A)/sizeof(double) vaudrait 3/2.

Jean-Marc Bourguet

unread,
Oct 9, 2012, 3:58:50 AM10/9/12
to
Olivier Miakinen <om+...@miakinen.net> 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).

>> Je ne connais pas d'archi ou sizeof(double) < sizeof(int), mais
>> pourquoi pas...
>
> ;-)
>
> Pourquoi pas, en effet, mais ce n'est pas là que serait le problème.
>
> Il y aurait problème si on avait sizeof(int) = 4, sizeof(double) = 8,
> mais alignement(int) = alignement(double) = 4. Dans ce cas, la taille
> de A serait de 12 octets, et sizeof(A)/sizeof(double) vaudrait 3/2.

Je pensais a ce cas. Il y a deux types de contraintes d'alignements.
Celles imposees (si on ne les respecte pas, ca crache). C'est
generalement la taille du type, mais dans le cas de types vectoriel, la
taille de l'element est un meilleur choix.

Puis celles pour des raisons de perf sur des archi qui n'ont pas de
contraintes dures. Ca va dependre pas mal de l'archi. La tendence
actuelle, c'est "tant que c'est dans une ligne de cache, ca ne change
pas les perfs". Pour les machines sans cache, ce qui compte, c'est
plutot le nombre d'acces a la memoire. Dans cette optique, avec un bus
donnee de 32 bits, tant que le double est aligne sur 4 bytes, ca ne
change pas le nombre de transfert necessaire, donc c'est une contrainte
potentielle. Puis on a des frontieres plus haut qui comme les lignes de
caches peuvent etre couteuses a franchir. Comme ces frontieres ne
traversent pas les lignes de cache, on en tient compte pour des donnees
plus grandes, et generalement uniquement a la main.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ

Lucas Levrel

unread,
Oct 9, 2012, 4:48:00 AM10/9/12
to
Le 8 octobre 2012, Olivier Miakinen a ᅵcrit :

> C'est un peu casse-gueule, tu ne crois pas ? Alors qu'il serait si
> simple d'avoir un pointeur sur A, que tu incrᅵmentes normalement,
> avant d'en extraire le deux ᅵ chaque tour de boucle.

Je pense que ma faᅵon de faire rᅵsulte en moins d'instructions, mais je
n'ai pas vᅵrifiᅵ sur le code assemblᅵ (bouh !).

--
LL

Lucas Levrel

unread,
Oct 9, 2012, 4:54:12 AM10/9/12
to
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

Lucas Levrel

unread,
Oct 9, 2012, 5:02:23 AM10/9/12
to
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

Lucas Levrel

unread,
Oct 9, 2012, 5:08:15 AM10/9/12
to

(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

Alain Ketterlin

unread,
Oct 9, 2012, 5:17:14 AM10/9/12
to
Lucas Levrel <lucas....@u-pec.fr> 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 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.

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.

-- Alain.

Marc Espie

unread,
Oct 9, 2012, 6:17:15 AM10/9/12
to
In article <pxb391o...@bourguet.org>,
Jean-Marc Bourguet <j...@bourguet.org> wrote:
>Olivier Miakinen <om+...@miakinen.net> 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)...

Lucas Levrel

unread,
Oct 9, 2012, 8:16:37 AM10/9/12
to
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

Alain Ketterlin

unread,
Oct 9, 2012, 8:50:41 AM10/9/12
to
Lucas Levrel <lucas....@u-pec.fr> 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 é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.

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 dire 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.

Jean-Marc Bourguet

unread,
Oct 9, 2012, 10:27:18 AM10/9/12
to
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).

Marc Espie

unread,
Oct 9, 2012, 10:58:52 AM10/9/12
to
In article <pxby5jf...@bourguet.org>,
Jean-Marc Bourguet <j...@bourguet.org> 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).

ptyxs

unread,
Oct 11, 2012, 11:23:20 AM10/11/12
to benoi...@free.fr
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'appeler
plutôt structure les classes qui ne possèdent que des données publiques.



ptyxs

unread,
Oct 11, 2012, 11:26:49 AM10/11/12
to benoi...@free.fr
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 ?
>
La seule différence entre classe et structure est que dans une structure
lorsque ce n'est pas précisé par une étiquette public: ou private: les
données ou fonctions sont par défaut publiques alors qu'elles seraient
privées dans une classe.
A part ça c'est la même chose...

ld

unread,
Oct 19, 2012, 6:32:19 AM10/19/12
to
On 9 oct, 16:58, es...@lain.home (Marc Espie) wrote:
> In article <pxby5jfyb3t....@bourguet.org>,
> Jean-Marc Bourguet  <j...@bourguet.org> 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.

je reste assez dubitatif sur les versions recentes (4.7). Les
performances se sont degradees par rapport a 4.5 sans compter les
bugs. J'ai un exemple recent ou appeler un printf en plein milieu d'un
calcul numerique augmente de 25% les performances du code. La raison
est que l'optimiseur de gcc 4.7 ne peut plus "fusionner" deux parties
de code qui sont semantiquement separees. L'appel d'une fonction
variadique avec effet de bord est vu comme un mur par l'optimiseur. Du
coup, il optimise mieux les deux parties separement comme il le
devrait et les performances sont meilleures.

> 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.

SSE possede aussi des instructions pour charger/sauver des donnees non
alignees comme _mm_loadu_pd. Certes il y a une legere perte de
performance, mais ca ne crashe pas.

> 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.

Il manque encore les flexible array members incompatible avec le
modele objet actuel. Indispensable pour de bonne performances sur de
petits objets dynamiques comme les strings ou les vecteurs.

> (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).

ld.

0 new messages