OVH Cloud OVH Cloud

Contigüité memoire ?

43 réponses
Avatar
May
Bonjour,

J'utilise une classe de base tres simple :

struct donne
{
double Int;
double Ext;
double IntExt;
}

puis un tableau aloué statiquement pour le moment

donne Tab[1024];

Ma question est assez simple, dans quel ordre en memoire, sont les données ?
Est-ce que je peux faire un truc du genre :

double *ptr=&Tab[0].Int;
for (int i=0;i<256;i++,ptr+=3)
{
*ptr=1.0;
}

Afin d'initialiser tous les champ Int de toutes les classes du tableau ?
Et si oui est-ce que ca reste valable si je fait un tableau dynamique à la C
(new/delete) ? ou avec std::vector<donne> ?

Merci
May

10 réponses

1 2 3 4 5
Avatar
Christophe Lephay
"Christophe Lephay" a écrit dans le message
de news:bkpjkb$rli$
"Gabriel Dos Reis" a écrit dans le message de
news:
"Christophe Lephay" writes:
| Que se passe-t-il avec un
| tableau de char si chaque adresse doit être alignée, par exemple, sur
un


| multiple de 4 ? sizeof( char ) renverra-t-il 4 (au moins) ?

sizeof(char), par définition, vaut toujours 1.


Mais dans ce cas, comment peut-on avoir, avec char tab[ N ], &tab[
0 ]+sizeof( char ) == &tab[ 1 ] si chaque élément doit être aligné sur un
multiple de 4 ?

A moins que, avec char * ptr, ++ptr ne soit pas équivallent à ptr + > sizeof( char ) dans le cas où on a des contraintes d'alignement ?


Une autre possibilité qui me vient : sizeof( char ) == 1, mais avec 1 == 4
octets pour ce qui concerne l'arithmétique des pointeurs ?

Chris


Avatar
Gabriel Dos Reis
"Christophe Lephay" writes:

| "Gabriel Dos Reis" a écrit dans le message de
| news:
| > "Christophe Lephay" writes:
| > | Que se passe-t-il avec un
| > | tableau de char si chaque adresse doit être alignée, par exemple, sur un
| > | multiple de 4 ? sizeof( char ) renverra-t-il 4 (au moins) ?
| >
| > sizeof(char), par définition, vaut toujours 1.
|
| Mais dans ce cas, comment peut-on avoir, avec char tab[ N ], &tab[
| 0 ]+sizeof( char ) == &tab[ 1 ] si chaque élément doit être aligné sur un
| multiple de 4 ?

c'est pour ça que le compilateur est là. « aligner sur un multiple de
4 » est quelque chose que seul le compilateur (ou toi) comprend. C++
ne sait pas ce que c'est.
Si un char doit être aligné. sur 4, alors il le sera, qu tu écrives
ptr + 1 ou &tab[1].

<aparthé>
De manière interne, un compilateur connaît les alignements et traduit
les arithmétiques pointeuresques de manière adéquate et transparente
à l'utilisateur.
</aparthé>

-- Gaby
Avatar
Gabriel Dos Reis
"Christophe Lephay" writes:

| "Christophe Lephay" a écrit dans le message
| de news:bkpjkb$rli$
| > "Gabriel Dos Reis" a écrit dans le message de
| > news:
| > > "Christophe Lephay" writes:
| > > | Que se passe-t-il avec un
| > > | tableau de char si chaque adresse doit être alignée, par exemple, sur
| un
| > > | multiple de 4 ? sizeof( char ) renverra-t-il 4 (au moins) ?
| > >
| > > sizeof(char), par définition, vaut toujours 1.
| >
| > Mais dans ce cas, comment peut-on avoir, avec char tab[ N ], &tab[
| > 0 ]+sizeof( char ) == &tab[ 1 ] si chaque élément doit être aligné sur un
| > multiple de 4 ?
| >
| > A moins que, avec char * ptr, ++ptr ne soit pas équivallent à ptr + | > sizeof( char ) dans le cas où on a des contraintes d'alignement ?
|
| Une autre possibilité qui me vient : sizeof( char ) == 1, mais avec 1 == 4
| octets pour ce qui concerne l'arithmétique des pointeurs ?

oui.

-- Gaby
Avatar
Mickael Pointier
struct donne
{
double Int;
double Ext;
double IntExt;
}
[..]
Ma question est assez simple, dans quel ordre en memoire, sont les
données ? Est-ce que je peux faire un truc du genre :

double *ptr=&Tab[0].Int;
for (int i=0;i<256;i++,ptr+=3)
[..]


Non, car tu n'as aucune garantie que sizeof(donne)==3; Sur un système
32 bits par exemple, ce ne serait pas étonnant que sizeof(donne)==4;


C'est moi qui suit dans la quatrième dimension ???

Disons sur un PC x86 en Win32, sizeof(double) ca vaut 8 (et
sizeof(float) vaut 4).

Si je fait sur mon PC sizeof(donne) j'obtient 24.

sizeof() ca donne bien la taille (paddée) de la somme des tailles des
éléments, non ??? Ca donne pas le nombre d'élément ?

Mike (y'a des jours où je comprend plus rien, non, c'est pas le 1er
avril)


Avatar
Gabriel Dos Reis
"Mickael Pointier" writes:

| Gabriel Dos Reis wrote:
| > Samuel Krempp writes:
| >
| >> le Tuesday 23 September 2003 13:59,
| >> écrivit :
| >>
| >>>> double *ptr=&Tab[0].Int;
| >>>> for (int i=0;i<256;i++,ptr+=3)
| >>>
| >>> for (int i = 0; i < 256; ++i, ptr += sizeof (donne))
| >>
| >> mais là je pense que tu as oublié de déclarer ptr comme tu le veux au
| >> préalable :
| >> void * ptr
| >> (et il faut faire des casts dans la boucle)
| >
| > Non. Je n'ai rien oublié. En fait, déclarer ptr de type « void* » rend
| > l'arithmétique invalide.
|
| J'ai du louper un morceau.
|
| "ptr" est bien un pointeur sur double, et "donne" une structure
| contenant trois doubles, qui donc a priori ne vaut pas moins de
| 3*sizeof(double), non ?

absolument exact.

| Je suis d'accord que sizeof(donne) est bien de combien on doit sauter
| (en octets) pour aller d'une structure à une autre, mais si le pointeur
| est en "double", en ajoutant "sizeof(donne)" tu ne vas pas à la
| structure suivante, tu vas 3 fois plus loins que voulu. Non ?

encore, absolument exact.

J'aurais dû avoir écrit

for (int i = 0; i < 256; ++i, ptr += sizeof (donne))
((double *) ptr)->Int = 1.0;

avec char* ptr = (char*) tab[0];

| Moi j'aurais plutot vu ca:
|
| donne *ptr=&Tab[0];
| for (int i = 0; i < 256; ++i, ptr++)
| {
| ptr->Int=1.0;
| }

c'est essentiellement ce que j'ai proposé.

-- Gaby
Avatar
Gabriel Dos Reis
Samuel Krempp writes:

| le Tuesday 23 September 2003 15:58, écrivit :
|
| > Samuel Krempp writes:
| >
| > | le Tuesday 23 September 2003 13:59, écrivit :
| > |
| > | > | double *ptr=&Tab[0].Int;
| > | > | for (int i=0;i<256;i++,ptr+=3)
| > | >
| > | > for (int i = 0; i < 256; ++i, ptr += sizeof (donne))
| > |
| > | mais là je pense que tu as oublié de déclarer ptr comme tu le veux au
| > | préalable :
| > | void * ptr
| > | (et il faut faire des casts dans la boucle)
| >
| > Non. Je n'ai rien oublié. En fait, déclarer ptr de type « void* » rend
| > l'arithmétique invalide.
|
| ah, alors en char *.

c'est exact -- voir le message de Mike et mon followup.

|
| en tout cas tel quel, ptr va aller en dehors de la mémoire allouée à
| donne Tab[1024];
| pour peu qu'on aie
| 256 * sizeof(donnee)*sizeof(double) > 1024 * sizeof(donnee)
|
| ie : sizeof(double) > 4

c'est exact.

-- Gaby
Avatar
Arnaud Debaene
Gabriel Dos Reis wrote:
"Mickael Pointier" writes:

Mike (y'a des jours où je comprend plus rien, non, c'est pas le
1er avril)


Y a des jours où certains d'entre nous doivent rester au lit :-(

Argh, oui exact, j'ai raconté n'importe quoi :-(. Bon on reprend : rien ne

garnatit que sizeof(donne) = 3* izeof(double).

Arnaud


Avatar
Gabriel Dos Reis
"Arnaud Debaene" writes:

| Gabriel Dos Reis wrote:
| > "Mickael Pointier" writes:
| >
| >> Mike (y'a des jours où je comprend plus rien, non, c'est pas le
| >> 1er avril)
| >
| > Y a des jours où certains d'entre nous doivent rester au lit :-(
| >
| Argh, oui exact, j'ai raconté n'importe quoi :-(.

je parlais de moi en premier...

-- Gaby
Avatar
kanze
"Mickael Pointier" wrote in message
news:<bkpjae$qgk$...
Gabriel Dos Reis wrote:
Samuel Krempp writes:

le Tuesday 23 September 2003 13:59,
écrivit :

double *ptr=&Tab[0].Int;
for (int i=0;i<256;i++,ptr+=3)


for (int i = 0; i < 256; ++i, ptr += sizeof (donne))
mais là je pense que tu as oublié de déclarer ptr comme tu le veux

au préalable :
void * ptr
(et il faut faire des casts dans la boucle)


Non. Je n'ai rien oublié. En fait, déclarer ptr de type « void* »
rend l'arithmétique invalide.


J'ai du louper un morceau.


Seulement le fait que Gaby n'a pas dormi hier soir, ou quelque chose de
semblable. C'est rare qu'il se plante dans quelque chose d'aussi gros,
mais c'est la seconde fois aujourd'hui.

"ptr" est bien un pointeur sur double, et "donne" une structure
contenant trois doubles, qui donc a priori ne vaut pas moins de
3*sizeof(double), non ?

Je suis d'accord que sizeof(donne) est bien de combien on doit sauter
(en octets) pour aller d'une structure à une autre, mais si le
pointeur est en "double", en ajoutant "sizeof(donne)" tu ne vas pas à
la structure suivante, tu vas 3 fois plus loins que voulu. Non ?

Moi j'aurais plutot vu ca:

donne *ptr=&Tab[0];
for (int i = 0; i < 256; ++i, ptr++)
{
ptr->Int=1.0;
}


Par exemple.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16





Avatar
Samuel Krempp
Ca dépend donc du contexte. May, y-a-t-il en effet une raison pour
laquelle

tu veux itérer sur un pointeur vers double plutôt que de passer par
Tab[i].Int ?

--
Sam


Désolée, j'ai eu une coupure reseau cette journée
Effectivement , je veux utiliser la Vector Math Library de la MKL pour
"unpack" un tableau de double dans un tableau d'objets de 3 doubles.

En fait j'ai un tableau de double nommé Int a mettre dans tous les champs
Int des mes classes "donne".
Pour cela la MKL propose une fonction unpack dans la sous librairie VML
mais pour cela j'ai besoin d'un offset constant.

Tout le probleme est affaire de performance la MKL utilisant le cache L2
du processeur, c'est en moyenne 3 fois plus rapide qu'une boucle "for"
(comme proposé).

J'espere etre claire .... c'est pas sur


si si, je vois la situation.

alors comme je disais, le tout est de t'assurer que sizeof(donne) est un
multiple de sizeof(double)
Si c'est un programme que tu dois juste compiler toi-même, tu peux supposer
que c'est le cas et faire :

#include <cassert>
double *ptr=&Tab[0].Int;
assert(sizeof(donnee) % sizeof(double) == 0);
for (int i=0;i<256;i++,ptr+= sizeof(donnee)/sizeof(double))
[..]

concrètement, je m'attends à ce que ça marche sur des PC quel que soit le
compilateur (et on aura bien n=3), mais je suis pas expert en la matière.

Si l'assertion échoue, ou que tu veux que le programme soit sûr de marcher
ailleurs, il faudrait ajouter un tableau char[n] dans le struct donnee, en
choisissant le n pour que l'assertion soit vraie.

par exemple :

struct Donnee {
    double Int;
    double Ext;
    double IntExt;

struct Donnee_non_alignee { double x, y, z; };
enum {
ncompl=sizeof(double)-sizeof(Donnee_non_alignee)%sizeof(double)
};
char complement[ncompl];
}


On peut espèrer que là, sizeof(Donnee) sera toujours un multiple de
sizeof(double) et que itérer avec += sizeof(Donnee)/sizeof(double)
marchera. mais je suis pas certain que soit garanti.. Quelqu'un peut
confirmer ?

--
Sam


1 2 3 4 5