Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Organisation mémoire d'une structure

8 réponses
Avatar
Vincent
Bonjour,

Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'elle
prendra en mémoire?

struct toto {
int a;
char nom[4];
int b;
};

Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.

void InitIcmpHeader(char *buf, int datasize)
{
ICMP_HDR *icmp_hdr=NULL;
char *datapart=NULL;

icmp_hdr = (ICMP_HDR *)buf;
icmp_hdr->icmp_type = ICMPV4_ECHO_REQUEST_TYPE; //
request an ICMP echo
icmp_hdr->icmp_code = ICMPV4_ECHO_REQUEST_CODE;
icmp_hdr->icmp_id = (USHORT)GetCurrentProcessId();
icmp_hdr->icmp_checksum = 0;
icmp_hdr->icmp_sequence = 0;

datapart = buf + sizeof(ICMP_HDR);
//
// Place some data in the buffer.
//
memset(datapart, 'E', datasize);
}

J'en conclus, que les données membre de la structure doivent
impérativement être contigue en mémoire.

Me trompe-je?

VB

8 réponses

Avatar
Alexandre Bacquart
Vincent wrote:
Bonjour,

Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'elle
prendra en mémoire?



En aucun cas.

struct toto {
int a;
char nom[4];
int b;
};

Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.

void InitIcmpHeader(char *buf, int datasize)
{
ICMP_HDR *icmp_hdr=NULL;
char *datapart=NULL;

icmp_hdr = (ICMP_HDR *)buf;
icmp_hdr->icmp_type = ICMPV4_ECHO_REQUEST_TYPE; //
request an ICMP echo
icmp_hdr->icmp_code = ICMPV4_ECHO_REQUEST_CODE;
icmp_hdr->icmp_id = (USHORT)GetCurrentProcessId();
icmp_hdr->icmp_checksum = 0;
icmp_hdr->icmp_sequence = 0;

datapart = buf + sizeof(ICMP_HDR);
//
// Place some data in the buffer.
//
memset(datapart, 'E', datasize);
}

J'en conclus, que les données membre de la structure doivent
impérativement être contigue en mémoire.



Pourquoi cette conclusion ? Le remplissage est effectué à travers un
pointeur de type ICMP_HDR. Aucun problème.

Par contre, le memset() opère sur le buffer *après* la place occupée par
ICMP_HDR, et les 'E' écrits ici seront contigus (il ne s'agit plus de
structure, mais d'un tableau de char).

Tout se passe comme prévu tant que la taille de buf est effectivement au
moins égale à sizeof(ICMP_HDR) + datasize.

Me trompe-je?



Vraisemblablement.


--
Alex
Avatar
espie
In article <49f959ec$0$20667$,
Vincent wrote:
Bonjour,

Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'elle
prendra en mémoire?



Non, pas de facon portable.

struct toto {
int a;
char nom[4];
int b;
};



Tout ce que te dit la norme, c'est:
- les champs seront dans le meme ordre en memoire que dans ta structure.
- le premier champ est a la meme adresse que la structure elle-meme.

Pour le reste, c'est dependant de l'implementation. Il peut y avoir des
octets de bourrage qui s'inserent pour garantir l'alignement par exemple.
(typiquement, sur pas mal d'archi, un int doit avoir une adresse multiple
de 2 ou de 4, sinon, soit ca fait une bus-error, soit c'est pas du tout
efficace en pratique parce qu'il faut recuperer deux mots memoire au lieu
d'un.

Notons que ces octets de bourrage "n'existent pas" au niveau du langage,
ce qui fait que deux struct peuvent avoir les memes champs mais ne pas etre
identiques (au sens de memcmp).

i.e.,

#include <string.h>
struct p
{
char a;
int b;
};

int
f()
{
struct p v1, v2;

v1.a = 0; v1.b = 0;
v2.a = 0; v2.b = 0;
return memcmp(&v1, &v2, sizeof(v1));
}

a de fortes chances de renvoyer autre chose que 0...


Certains compilateurs te donnent des extensions (__packed,
__attribute__((__packed__)) ) qui peuvent enlever certains octet de bourrage,
mais ca n'a rien de portable, et c'est souvent sournois.


Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.



Oui, c'est tres certainement du code non portable, et qui va avoir tendance
a dependre fortement, et de la plateforme, et du compilateur utilise.

Note: le langage te donne sizeof() pour savoir combien de place prend
ta structure en memoire (compte en char, sizeof(char) == 1 par definition),
et tu as eventuellement, offsetof(struct, champ) pour savoir ou se situe
un champ dans une structure.
Avatar
Alexandre Bacquart
Marc Espie wrote:
Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.



Oui, c'est tres certainement du code non portable, et qui va avoir tendance
a dependre fortement, et de la plateforme, et du compilateur utilise.



Je conçois très bien que si l'appelant cherche ensuite à envoyer buf tel
quel sur un flux attendant une forme compacte, des problèmes puissent
survenir, mais j'ai du mal à voir en quoi le code de la fonction n'est
pas portable. Des précisions ?

--
Alex
Avatar
espie
In article <49fa404b$0$18755$,
Alexandre Bacquart wrote:
Marc Espie wrote:
Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.







Oui, c'est tres certainement du code non portable, et qui va avoir tendance
a dependre fortement, et de la plateforme, et du compilateur utilise.





Je conçois très bien que si l'appelant cherche ensuite à envoyer buf tel
quel sur un flux attendant une forme compacte, des problèmes puissent
survenir, mais j'ai du mal à voir en quoi le code de la fonction n'est
pas portable. Des précisions ?



Ah, ta fonction elle-meme est portable. C'est ce qu'on en fait qui va souvent
ne pas l'etre, style envoyer directement ce contenu memoire sur ta carte
reseau.
Avatar
Alexandre Bacquart
Marc Espie wrote:
In article <49fa404b$0$18755$,
Alexandre Bacquart wrote:
Marc Espie wrote:
Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-tête
nécessaire.







Oui, c'est tres certainement du code non portable, et qui va avoir tendance
a dependre fortement, et de la plateforme, et du compilateur utilise.





Je conçois très bien que si l'appelant cherche ensuite à envoyer buf tel
quel sur un flux attendant une forme compacte, des problèmes puissent
survenir, mais j'ai du mal à voir en quoi le code de la fonction n'est
pas portable. Des précisions ?



Ah, ta fonction elle-meme est portable. C'est ce qu'on en fait qui va souvent
ne pas l'etre, style envoyer directement ce contenu memoire sur ta carte
reseau.



Nous sommes d'accord.


--
Alex
Avatar
-ed-
On 30 avr, 09:57, Vincent wrote:

Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'e lle
prendra en mémoire?



Exacte, non. Tout ce que dit la norme, c'est que le premier élément de
la structure a la même adresse que la structure elle même, et que
l'ordre des éléments est celui indiqué dans la définition. Si on ve ut
connaitre l'emplacement relatif de chaque champ par rapport au
premier, on peut utiliser offsetof() qui est définie dans <stddef.h>.
Cette macro indique la position en nombre de bytes. La valeur exacte
dépend de l'implémentation et ne peut être prévue.

Cette question me viens après avoir parcouru un bout de code venant de
PSDK. Cette fonction InitIcmpHeader(), de ce que j'en comprend, Affecte
à des endroits bien particulier d'un buffer, les information d'en-têt e
nécessaire.

void InitIcmpHeader(char *buf, int datasize)
{
     ICMP_HDR   *icmp_hdr=NULL;
     char       *datapart=NULL;

     icmp_hdr = (ICMP_HDR *)buf;
     icmp_hdr->icmp_type     = ICMPV4_ECHO_REQUEST_TYPE;        //
request an ICMP echo
     icmp_hdr->icmp_code     = ICMPV4_ECHO_REQUEST_CODE;
     icmp_hdr->icmp_id       = (USHORT)GetCurrentProcessId( );
     icmp_hdr->icmp_checksum = 0;
     icmp_hdr->icmp_sequence = 0;

     datapart = buf + sizeof(ICMP_HDR);
     //
     // Place some data in the buffer.
     //
     memset(datapart, 'E', datasize);

}

J'en conclus, que les données membre de la structure doivent
impérativement être contigue en mémoire.



Consécutives, oui. contiguë, non. Ce que tu voies est une
implémentation particulière. Ce n'est pas du code portable.
Avatar
Antoine Leca
Le 30/04/2009 22:48, Marc Espie écrivit :
In article <49f959ec$0$20667$, Vincent wrote:
Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'elle
prendra en mémoire?



Non, pas de facon portable.

Tout ce que te dit la norme, c'est:
- les champs seront dans le meme ordre en memoire que dans ta structure.
- le premier champ est a la meme adresse que la structure elle-meme.



- si on définit une autre structure, même avec un nom différent, mais
avec les mêmes définitions de membres (et le même compilateur, mêmes
options de compilation), alors l'organisation mémoire sera la même
pour les deux structures. Cela reste vrai (pour la partie commune,
évidemment) même si l'une des deux structures compte plus de membres


Antoine
Avatar
espie
In article <gteseo$d06$,
Antoine Leca wrote:
Le 30/04/2009 22:48, Marc Espie écrivit :
In article <49f959ec$0$20667$, Vincent wrote:
Lors de l'utilisation d'une structure du type de celle ci-dessous,
est-ce qu'un élément de la norme prévois l'organisation exacte qu'elle
prendra en mémoire?



Non, pas de facon portable.

Tout ce que te dit la norme, c'est:
- les champs seront dans le meme ordre en memoire que dans ta structure.
- le premier champ est a la meme adresse que la structure elle-meme.



- si on définit une autre structure, même avec un nom différent, mais
avec les mêmes définitions de membres (et le même compilateur, mêmes
options de compilation), alors l'organisation mémoire sera la même
pour les deux structures. Cela reste vrai (pour la partie commune,
évidemment) même si l'une des deux structures compte plus de membres



Oui, aussi ! je le sais, j'avais juste oublie de le mentionner. Sinon,
bon courage pour faire de l'objet avec heritage en C...