OVH Cloud OVH Cloud

Taille d'une structure

12 réponses
Avatar
Matt
Bonjour,

un petit soucis :

#include <iostream>

struct Entete
{
char toto[5];
long tata;
};


int main(void)
{
Entete titi;

std::cout << "Taille d'un long : " << sizeof(long) << std::endl
// Ca me retourne 4 octets : OK
<< "Taille d'un char[5] : " << sizeof(char[5]) << std::endl
// Ca me retourne 5 octets : OK
<< "Taille de la structure : " << sizeof(titi) << std::endl;
// Ca me retourne 12 octets ???

return 0;
}

Pourquoi cette difference de taille et une autre question quand je veux
faire
titi.toto = "tyty";

Il me dit que titi.toto doit etre une l-value ???
pourquoi je ne peux affecter "tyty" a titi.toto ???

Ce que je veux faire c'est une structure contenant le format d'une entete
d'un fichier WAVE
et de pouvoir la modifier par la suite pour la mettre dans une fichier
(logique !!!).

Merci pour vos réponses

Matt...

2 réponses

1 2
Avatar
kanze
"Matt" wrote in message
news:<4002454b$0$22324$...
|> >>Tu dois utiliser strcpy(titi.toto,"tyty");

|> > strncpy, plutôt, puisque la taille du tableau d'arrivée est
|> > fixe. strcpy ne fait pas de contrôle sur la taille du tableau
|> > à copier.

|> mieux : memcpy, pour éviter de controler sans cesse que dans
|> "tyty" il y ait un ''

Et pour accéder au délà de la fin du tableau si la source contient
moins d'octets qu'il n'en faut.

La réponse de Fabien a l'avantage d'être correcte du point de vue du
langage. Reste à voir s'il convient au cahier de charges -- on ne
sait pas encore ce qu'on veut exactement.


J'ai retenu la réponse de fabien strncpy qui est très bien.

En fait, ma structure est un format d'entête wave. Je voulais
réserver l'espace nécessaire en début de fichier avant de mettre
les échantillons et enfin rajouter dans l'entête les
renseignements obtenus a la fin de l'enregistrement...(Taille
fichier, taille échantillons ...) Puis toujours avec cette
structure, récupérer les données pour en faire une lecture.

Il y a des chaînes de caractères (toujours sur 4 octets), des long
et des short... mais j'ai toujours quelques soucis pour la taille
de ma structure car elle doit faire une taille (44 octets) et ni
plus ni moins.


Quand il s'agit d'écrire un nombre exact d'octets dans un fichier (ou
sur le reseau), la meilleur solution reste toujours à écrire tant
d'octets, comme des octets. Si on a une chaîne de caractères, par
exemple, on pourrait faire quelque chose du genre :

void
writeString( ostream& dest, std::string const& source, int count )
{
std::string::const_iterator
i = source.begin() ;
while ( count > 0 ) {
dest.put( i == source.end() ? '': *i ++ ) ;
count -- ;
}
}

Pour des types autres que les chaînes de caractères, le problème est
plus complex, parce que les formats des entiers ne sont pas identiques
sur toutes les machines. Dans la pratique, si tu sais que tu n'aurais
jamais à porter que sur des machines couramment répandues, tu peux
supposer que le format interne est complément à deux, ce qui est aussi
le format le plus courant pour des valeurs binaires dans des fichiers ou
sur le reseau. (En ce qui concerne les machines plus exotiques, il en
existe où même la taille des bytes n'est pas huit bits.) Tu n'aurais
donc plus qu'à t'occuper de la taille (combien d'octets) et de l'ordre
des octets. Pour un entier de 4 octets, par exemple :

void
write4ByteInt( ostream& dest, long value )
{
assert( value <= 2147483647 && value >= -2147483648 ) ;
dest.put( static_cast< char >( (value >> 24) & 0xff ) ;
dest.put( static_cast< char >( (value >> 16) & 0xff ) ;
dest.put( static_cast< char >( (value >> 8) & 0xff ) ;
dest.put( static_cast< char >( (value ) & 0xff ) ;
}

(Cet exemple sort les octets le poids forts d'abord, c-à-d dans l'ordre
Internet. On inverse l'ordre des écritures pour les sortir poids faibles
d'abord.)

N'oublie pas que dans des cas comme ceci, il faut que le fichier soit
ouvert en binaire.

Souvent, on veut formatter tout un enrégistrement en mémoire, afin de
pouvoir l'écrire d'un coup. Dans ce cas, on peut très bien se servir
d'un vector<char>, en remplaçant les dest.put() par des
dest.push_back(). Sinon, formatter vers un char[], au moyen de
ostrstream, marche bien aussi ; si tu dois formatter certains champs
(par exemple, sortir des nombres en texte), c'est la seule solution
valable.

Le seul problème avec cette méthode, c'est qu'il devient rapidement
pénible (et une source d'erreurs) de compter tout à la main. C'est en
fait bien plus facile à le laisser faire par le compilateur, en écrivant
quelque chose du genre :

struct Header
{
char field1[ 5 ] ;
char field2[ 4 ] ;
// ...
} ;

Selon la norme, rien n'y est garantie. Le compilateur a le droit d'y
insérer des octets supplémentaire de rembourrage ou bon lui semble. Dans
la pratique, en revanche, j'ai d'assez bonnes expériences avec ça à
condition que tous les champs de la struct soit des char[] (et que des
char[]). Pour utiliser cette technique, les règles suivantes s'imposent :

- Tout au début du programme, il faut un assert que la taille de la
struct est bien celui que tu veux.

- On insère toujours les valeurs comme ci-dessus. Pas de memcpy ou
d'autres (au moins qu'on fasse un memcpy d'un champs déjà formatté).
Pour les sorties formattées, c'est toujours possible à faire des
choses du genre :

Header h ;
ostrstream s( h.field2, sizeof( h.field2 ) ) ;
s << setw( sizeof( h.field2 ) ) << valeur ;

C'est une utilisation particulière de strstream ; on ne peut pas la
remplacer par stringstream.

Mais dans l'ensemble, la première méthode est plus sûre, même si c'est
un peu plus fastidieux à mettre en oeuvre.

--
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
konroth
Matt a écrit:
Bonjour,

un petit soucis :

#include <iostream>

struct Entete
{
char toto[5];
long tata;
};


int main(void)
{
Entete titi;

std::cout << "Taille d'un long : " << sizeof(long) << std::endl
// Ca me retourne 4 octets : OK
<< "Taille d'un char[5] : " << sizeof(char[5]) << std::endl
// Ca me retourne 5 octets : OK
<< "Taille de la structure : " << sizeof(titi) << std::endl;
// Ca me retourne 12 octets ???

return 0;
}

Pourquoi cette difference de taille et une autre question quand je veux
faire
titi.toto = "tyty";

Il me dit que titi.toto doit etre une l-value ???
pourquoi je ne peux affecter "tyty" a titi.toto ???

Ce que je veux faire c'est une structure contenant le format d'une entete
d'un fichier WAVE
et de pouvoir la modifier par la suite pour la mettre dans une fichier
(logique !!!).

Merci pour vos réponses

Matt...





---------------------------------------------------------------------------------------
on peux choisir dans les 'compiler options' les 'struct member alingement'.
Visual c++ 6 default c'est huit(8) byte. Ca explique la "fausse" taille.

excusez mon francais
---------------------------------------------------------------------------------------

1 2