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

help problème sizeof struct !!!

13 réponses
Avatar
Vincent
bonjour,

Voici mon problème :

soient :

struct S1
{
int toto;
}mytruc;

struct S2
{
short titi;
}mytruc2;

struct S3
{
int toto;
short titi;
}mytruc3

sizeof(S1) donne 4;
sizeof(S2) donne 2;
sizeof(S3) donne 8 ?????!!!!!

Où est l'erreur ?

quand je fait un read dans un fichier avec S3, çà donne forcement un truc
bizare ?

une idée ?

merci

Vincent

10 réponses

1 2
Avatar
Anthony Fleury
bonjour,


Bonsoir,

Voici mon problème :
soient :

struct S1
{
int toto;
}mytruc;

struct S2
{
short titi;
}mytruc2;

struct S3
{
int toto;
short titi;
}mytruc3

sizeof(S1) donne 4;
sizeof(S2) donne 2;
sizeof(S3) donne 8 ?????!!!!!


Normal...

Où est l'erreur ?


Il n'y a pas d'erreurs. En fait, la taille d'une structure est
supérieure ou égale à la somme des tailles de ses élements.
La seule chose qu'on sait c'est que le premier élement sera toujours à
l'adresse de la structure, pour les autres élements, il peut y avoir ce
que l'on appelle des bits de padding, ou bits de remplissage entre les
deux, afin que les élements soient alignés correctement sur l'architecture.

quand je fait un read dans un fichier avec S3, çà donne forcement un truc
bizare ?


Ca ne pose pas de problème dans le cas où, comme c'est recommandé pour
le fread/fwrite, la lecture se fait sur la même architecture que
l'écriture. Sur une architecture donnée, la structure aura toujours la
même taille, et les bits de paddings seront pris en compte par
fread/fwrite. Il va écrire toute la structure, y compris le padding, et
relire le tout. Voilà.
Et dans le cas d'un changement de taille de S3, ca veut dire qu'on
change d'architecture, et donc le fread/fwrite n'était de toute facon
pas portables. Il faut dans ce cas faire des fonctions de sérialisation
pour la structure ou la classe en question.

--
Anthony Fleury

Avatar
Fabien LE LEZ
On Wed, 23 Nov 2005 21:33:50 +0100, "Vincent" :

quand je fait un read dans un fichier avec S3


Faut pas le faire.

Avatar
Fabien LE LEZ
On Wed, 23 Nov 2005 21:53:15 +0100, Anthony Fleury :

Sur une architecture donnée, la structure aura toujours la
même taille, et les bits de paddings seront pris en compte par
fread/fwrite. Il va écrire toute la structure, y compris le padding, et
relire le tout. Voilà.


Attention : le terme "architecture" est trompeur.
Si jamais le compilateur change, ou la version dudit compilateur, ou
les options de compilation, le padding peut changer.

En gros, si tu mets ton compilateur à jour, les fichiers de données
peuvent très bien se retrouver illisibles.

Avatar
Vincent
"Fabien LE LEZ" a écrit dans le message de news:

On Wed, 23 Nov 2005 21:33:50 +0100, "Vincent" :

quand je fait un read dans un fichier avec S3


Faut pas le faire.



Merci beaucoup ! c'est tout à fait çà ( j'ai presque passé la journée
dessus)
j'ai remplacé le sizeof par la taille que je connais et les choses sont dèjà
mieux.
Le fichier est issu d'un autre logiciel ( un truc en fortran), en plus mon
programme doit tourner sous unix
Solaris ( j'ai du aussi tenir compte si big ou little indian !)
J'arrive enfin à lire l'entête correctement ( reste plus que les données
:) )

Merci encore ( je vais me coucher heureux)

Vincent


Avatar
Fabien LE LEZ
On Wed, 23 Nov 2005 22:08:21 +0100, "Vincent" :

Le fichier est issu d'un autre logiciel ( un truc en fortran)


Faut lire octet par octet, et reconstituer les entiers un par un (à
grands coups de "<< CHAR_BIT"). Ainsi, tu n'auras même pas à te
préoccuper de l'endianness de l'OS -- uniquement du format utilisé
dans le fichier.
Note : utilise si possible des entiers non signés -- ça évite bien des
déboires.

Avatar
kanze
Fabien LE LEZ wrote:
On Wed, 23 Nov 2005 22:08:21 +0100, "Vincent" :

Le fichier est issu d'un autre logiciel ( un truc en fortran)


Faut lire octet par octet, et reconstituer les entiers un par
un (à grands coups de "<< CHAR_BIT").


Sauf que ce n'est pas CHAR_BIT, qui donne le nombre de bits sur
la machine, qu'on veut ici, mais le nombre de bits qu'on lit à
chaque coup de la représentation externe.

Dans prèsque tous les cas, on peut utiliser 8, ou CHAR_BIT (qui
vaudrait 8), sans problème. Si on se trouver sur un processeur 9
bits, en revanche, et le processeur qui a écrit les données n'en
a écrit que 8, c'est bien de 8 qu'il faut décaler. Et dans le
cas inverse, on l'a dans le baba -- il faut voir ce que fait le
hardware et le système avec le bit qui n'y passe pas.

Dans la pratique, je vais ignorer les problèmes des différentes
tailles de byte, jusqu'au jour où je ne le peux pas. Qui
n'arrivera probablement jamais.

(Pour la reste, évidemment, je suis entièrement d'accord avec ce
que tu dis.)

Ainsi, tu n'auras même pas à te préoccuper de l'endianness de
l'OS -- uniquement du format utilisé dans le fichier. Note :
utilise si possible des entiers non signés -- ça évite bien
des déboires.


Au niveau de l'écriture de la lecture, en tout cas. Note que les
règles de C++ font que si tu convertis une valeur signée en le
type correspondant non signé, les bits du résultat seront
exactement ceux de la valeur initiale, en format complément à
deux. Donc, si le format externe est complément à deux (c'est le
cas, par exemple, des entiers sur l'Internet), tu as « encodé »
correctement automatiquement.

Formellement, la conversion des non-signés en signé de la même
taille a un comportement dépendant de l'implémentation.
Pratiquement, toutes les implémentations que je connais font
qu'une conversion signée vers non-signée, puis de rétour à
signée garde la valeur. Ce qui veut dire que si tu écris le
signé comme non-signé, puis le rélire comme non-signé et
réconvertit en signé, tu te rétrouves avec la bonne valeur.

Ici aussi, c'est plus d'informations qu'il n'en faut pour la
plupart des gens. Tant qu'on reste sur les archictures
« courante », et qu'on s'assure qu'on lit et qu'on écrit des
données de la même taille (qui serait 8, 16, 32 ou 64 bits), on
n'aura pas de problèmes. Formellement, je dirais qu'on doit
documenter cette restriction, mais dans la pratique, tant que je
ne sais pas que le code a réelement fonctionné sur une machine
avec des bytes de 9 bits, ou à complément à un, je suppose que
cette restriction existe, et que le code ne fonctionnera pas
d'office sur une telle machine.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Eric Pruneau
"Vincent" a écrit dans le message de news:
4384d22f$0$6682$
bonjour,

Voici mon problème :

soient :

struct S1
{
int toto;
}mytruc;

struct S2
{
short titi;
}mytruc2;

struct S3
{
int toto;
short titi;
}mytruc3

sizeof(S1) donne 4;
sizeof(S2) donne 2;
sizeof(S3) donne 8 ?????!!!!!

Où est l'erreur ?

quand je fait un read dans un fichier avec S3, çà donne forcement un truc
bizare ?

une idée ?

merci

Vincent


Pour contourner ce problème, tu peux utiliser

#pragma pack(1)

Ce qui force l'alignement des données sur 1 bits. Probablement que ton
compilateur
fait de l'alignement sur 8 bits par défaut.

avec pragma pack(1), les size de tes structures vont donner ce a quoi tu
t'attend.
tu peut remettre
#pragma pack()
à la fin du fichier, pour que l'alignement retourne a la valeur par défaut.

Note: Ceci marche bien avec VC++, je sais pas trop avec un autre compilateur
il y a
peut-etre des petites différences...

Eric

Avatar
Fabien LE LEZ
On 24 Nov 2005 00:03:25 -0800, "kanze" :

Dans la pratique, je vais ignorer les problèmes des différentes
tailles de byte, jusqu'au jour où je ne le peux pas. Qui
n'arrivera probablement jamais.


Idem. En fait, je considère (peut-être à tort) que CHAR_BIT est
systématiquement 8 sur toutes les machines concernées par mon code
(Pour l'instant, c'est des machines compatibles i386, donc je ne cours
pas trop de risques ;-) )

Néanmoins, j'utilise CHAR_BIT parce que "8" est une "magic value".

Avatar
Fabien LE LEZ
On Thu, 24 Nov 2005 09:44:03 -0500, "Eric Pruneau"
:

#pragma pack(1)

Note: Ceci marche bien avec VC++, je sais pas trop avec un autre compilateur


Je confirme que les "#pragma" sont totalement dépendants du
compilateur.

Si un compilo ne comprend pas une directive #pragma, il l'ignorera
tout simplement (avec éventuellement un warning).

Le danger peut résider dans le fait qu'une directive #pragma donnée
puisse vouloir dire une chose sur un compilateur et tout à fait autre
chose sur un autre compilateur, mais je n'ai pas encore rencontré ce
cas.

Avatar
loic.actarus.joly


Dans la pratique, je vais ignorer les problèmes des différentes
tailles de byte, jusqu'au jour où je ne le peux pas. Qui
n'arrivera probablement jamais.


Avec un petit static_assert ?

--
Loïc

1 2