OVH Cloud OVH Cloud

Taille de structure

40 réponses
Avatar
laurent Coanet
J'ai un petit problème avec la taille des structures contenant des char :

typedef struct {
unsigned char c1;
unsigned char c2;
} MaStruct;

un sizeof(MaStruct) renvoie 4 et non le 2 attentu... ce qui me pose problème
pour lire un fichier dont l'entête commence par des informations codées sur
un octet (et je n'ai évidement pas envie de lire chaque info une à une).

Comment résoudre ou détourner ce problème ?

10 réponses

1 2 3 4
Avatar
K. Ahausse
"laurent Coanet" a écrit dans le message de
news:c9nc87$492$
J'ai un petit problème avec la taille des structures contenant des char :

typedef struct {
unsigned char c1;
unsigned char c2;
} MaStruct;

un sizeof(MaStruct) renvoie 4 et non le 2 attentu... ce qui me pose
problème

pour lire un fichier dont l'entête commence par des informations codées
sur

un octet (et je n'ai évidement pas envie de lire chaque info une à une).

Comment résoudre ou détourner ce problème ?




Si la possibilité t'en es donnée : l'utilisation #pragma pack( ), permet de
forcer l'alignement.

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Alexandre BACQUART wrote:

Non seulement un int
(voire un char) n'a pas forcément la même taille d'une architecture à
l'autre (problème cependant facilement résolvable en C99 avec
int8_t...),


C'est pas vrai. Le langage C99 n'a pas le pouvoir de créer des types nouveaux
sur des architectures qui ne peuvent pas les implémenter (Sur un DSP
TMS320C64, il *n'existe pas* d'objets < 16 bits). Dans sa grande sagesse (et
celle des rédacteurs), le langage C99 *n'impose pas* les types à taille fixe.
Il dit simplement que *sur les architectures qui l'acceptent*, l'implémenteur
a le droit de définir des types à taille fixe. Ces types sont donc par nature
non portables (leur existence même dépend de l'architecture), et pour moi,
n'ont *aucun* intéret.

Au moins, un char, c'est un char, et je me f*us pas mal qu'il fasse 8 ou 128
bits.

Les types 'at_least' (int_least<bits>_t) me paraissent plus intelligents,
mais ils n'apportent rien sur le plan sémantique par rapport aux types
existants (à part pour les grands entiers, 64 ou 128 bits). Tout programmeur
C muni d'un cerveau en état de marche sait qu'un char est un 'at_least8', un
short et un int un 'at_least16' et un long un 'at_least32'.

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Régis Troadec" wrote:

Je dois etre fatigue mais c'est interessant. Oui sizeof(char) =1, mais
prenons un (unsigned) char sur par exemple 12 bits,
apres un fread() de 1 char ou un fgetc(), ca va bien pointer un byte
soit 12 bits plus loin, non ?


Il n'y a pas de 'bits en trop' dans les fichiers. Le bytes de flux font 8
bits (on peut même prononcer le mot maudit "octets"). Ces 8 bits rentrent
dans n'importe quel char qu'il fasse 8 ou 256 bits. C'est probablement pour
ça qu'un char doit faire 8 bits *minimum*.

Dans l'autre sens, seuls les 8 bits de poids faible seront écrits dans le
byte du flux.

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Vincent Lefevre <vincent+ wrote:

Non, aucun risque. Le mécanisme interne de lecture de flux est sur 8
bits quoiqu'il arrive.


Ce n'est pas dépendant de l'implémentation (même si en pratique,
c'est actuellement toujours 8 bits)?


En tout cas, seuls les 8 bits de poids faibles sont pris en compte.

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/


Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Richard Delorme wrote:

Donc, si je comprends ces paroles, pour ce programme :

#include <stdio.h>

int main(void) {
FILE *f;
unsigned char wdata = -1;
unsigned char rdata = 0;

f = fopen("test.dat", "wb");
fwrite(&wdata, 1, 1, f);
fclose(f);

f = fopen("test.dat", "rb");
fread(&rdata, 1, 1, f);
fclose(f);

printf("ecrit: %d, lu = %dn", wdata, rdata);

return 0;
}

dans l'hypothèse où toutes les I/O fonctionnent, on doit avoir, sur une
implémentation où CHAR_BITS vaut 12, l'affichage suivant :

ecrit: 4095, lu = 255

Or j'ai cru comprendre, dans ce que dit la norme, que ce qui est lu doit
être égal à ce qui a été écrit par la même implémentation :

7.19.2 Streams

[#3] A binary stream is an ordered sequence of characters
that can transparently record internal data. Data read in
from a binary stream shall compare equal to the data that
were earlier written out to that stream, under the same
implementation. [...]

Donc on devrait plutôt avoir :

ecrit: 4095, lu = 4095

Non ?


Non. La transparence vaut pour des *caractères* (characters). La valeur max
d'un caractère est 255.

characters != char

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Antoine Leca
En , Emmanuel Delahaye va
escriure:
In 'fr.comp.lang.c', Alexandre BACQUART wrote:

Non seulement un int
(voire un char) n'a pas forcément la même taille d'une architecture à
l'autre (problème cependant facilement résolvable en C99 avec
int8_t...),


C'est pas vrai.


Ce n'est pas incompatible, c'est juste une différence de pouillèmes sur le
coefficient de portabilité, genre 0,0006% au lieu de 0,00061% (et je suis
large). Si tu n'as pas la taille qui va bien sur ton architecture cible, tu
ne risques pas de pouvoir lire un fichier dont les structures sont découpées
de cette manière, en tous cas pas de manière « totalement portable ». Donc
de toutes manières tu vas te retrouver avec un code spécifique, et au moins
le code avec les int8_t fera joli enc ommentaires, à titre de doc, pour
celui qui va venir derrière essayer de dépiauter le souk le jour où cela va
foirer...

Cela étant, le conseil d'Alexandre passe sous silence les problèmes de
direction de stockage, ainsi que les problèmes de représentation des
quantités signées (quand on commence à chipoter sur les architectures où
char ne vaut pas 8 bits, il vaut mieux s'intéresser _aussi_ aux problèmes de
stockage des nombres négatifs. ÀMHA.)


Le langage C99 n'a pas le pouvoir de créer des types
nouveaux sur des architectures qui ne peuvent pas les implémenter
(Sur un DSP TMS320C64, il *n'existe pas* d'objets < 16 bits). Dans sa
grande sagesse (et celle des rédacteurs), le langage C99 *n'impose
pas* les types à taille fixe. Il dit simplement que *sur les
architectures qui l'acceptent*, l'implémenteur a le droit de définir
des types à taille fixe.


Cela va un poil plus loin que cela: si tu PEUX implémenter int8_t, tu DOIS
le faire.

Ces types sont donc par nature non portables
(leur existence même dépend de l'architecture), et pour moi, n'ont
*aucun* intéret.


Et hop, un bébé qui part avec l'eau du bain.


Au moins, un char, c'est un char, et je me f*us pas mal qu'il fasse 8
ou 128 bits.


Oui oui. C'est ce que l'on dit jusqu'au jour où on exécute un algorithme
parfaitement portable mais « calculé » pour des char sur 8 bits; par exemple
qui déclare un tableau d'actions à effectuer en fonction du code d'un
caractère.

Le code va ressembler à

f_action (* table) [1 << CHAR_BIT];
/*...*/
table[' '] = agir_espace;

/*...*/

int c;
if( (c = getchar() ) != EOF )
table[c]( /*..*/ );

Et quand tu vas lancer cela sur ton bidule avec ses char 32 bits (avec 128
cela va vautrer immédiatement, c'est pas drôle), tu vas attendre 2 plombes
que l'OS ait fini d'allouer les 16G de mémoire virtuelle en swappant comme
un malade...


Les types 'at_least' (int_least<bits>_t) me paraissent plus
intelligents, mais ils n'apportent rien sur le plan sémantique par
rapport aux types existants (à part pour les grands entiers, 64 ou
128 bits).


Mouais. Je maintiens une bibliothèque supposément portable, qui manipulent
des entités dont le nombre peut dépasser 65000, mais est normalement de
l'ordre de 200 à 2000. Mes cibles sont les processeurs et OS actuels,
incluant donc MS-DOS, Win16, Amiga, tout autant que Alpha ou AMD64.
J'aimerais bien pouvoir utiliser uint_least32_t pour mes indices, moi, parce
que actuellement je suis « obligé » d'utiliser des unsigned long, et sur les
machines 64 bits qui peuvent facilement passer du 32 bits (genre AMD64),
unsigned long c'est pas vraiment optimum... (sauf chez M$, qui ont tellement
de unsigned long dans leur code qu'ils ont décidé de passer en force et de
garder les long à 32 bits de toutes manières... Là c'est sûr, int_leastxx_t
ne sert plus à rien. :-( )

Tout programmeur C muni d'un cerveau en état de marche
sait qu'un char est un 'at_least8', un short et un int un
'at_least16' et un long un 'at_least32'.


Manifestement, près de Redmond, WA, ils manquent d'énergie pour les mettre
en état de marche. Cela doit être l'enrichissement des prix du pétrole.


Antoine


Avatar
Richard Delorme
In 'fr.comp.lang.c', "Régis Troadec" wrote:


Je dois etre fatigue mais c'est interessant. Oui sizeof(char) =1, mais
prenons un (unsigned) char sur par exemple 12 bits,
apres un fread() de 1 char ou un fgetc(), ca va bien pointer un byte
soit 12 bits plus loin, non ?



Il n'y a pas de 'bits en trop' dans les fichiers. Le bytes de flux font 8
bits (on peut même prononcer le mot maudit "octets"). Ces 8 bits rentrent
dans n'importe quel char qu'il fasse 8 ou 256 bits. C'est probablement pour
ça qu'un char doit faire 8 bits *minimum*.

Dans l'autre sens, seuls les 8 bits de poids faible seront écrits dans le
byte du flux.


Donc, si je comprends ces paroles, pour ce programme :

#include <stdio.h>

int main(void) {
FILE *f;
unsigned char wdata = -1;
unsigned char rdata = 0;

f = fopen("test.dat", "wb");
fwrite(&wdata, 1, 1, f);
fclose(f);

f = fopen("test.dat", "rb");
fread(&rdata, 1, 1, f);
fclose(f);

printf("ecrit: %d, lu = %dn", wdata, rdata);

return 0;
}

dans l'hypothèse où toutes les I/O fonctionnent, on doit avoir, sur une
implémentation où CHAR_BITS vaut 12, l'affichage suivant :

ecrit: 4095, lu = 255

Or j'ai cru comprendre, dans ce que dit la norme, que ce qui est lu doit
être égal à ce qui a été écrit par la même implémentation :

7.19.2 Streams

[#3] A binary stream is an ordered sequence of characters
that can transparently record internal data. Data read in
from a binary stream shall compare equal to the data that
were earlier written out to that stream, under the same
implementation. [...]

Donc on devrait plutôt avoir :

ecrit: 4095, lu = 4095

Non ?

--
Richard


Avatar
Antoine Leca
En , Emmanuel Delahaye va escriure:
Les bytes des flux font toujours 8 bits (rien à voir avec le C).


En effet cela n'a rien à voir avec les flux ("streams") du C. Ceux-là sont
soit basés sur des char, soit basé sur des wchar_t (selon leur orientation,
cf fwide() et en général <wchar.h>).

Un autre concept existant en C est celui de fichier associé au flux. Ceux-ci
peuvent parfaitement être basés sur des unités de taille plus grandes ou
plus petites. Un exemple clairement énoncé par la norme est la possibilité
d'avoir un flux élargi associé à un fichier de "multibytes élargis" où le
code 0 est possible sans signifier '', ce qui suggère clairement la
possibilité d'une implémentation de stdio qui manipulent des fichiers textes
encodés en UTF-16.


Antoine

Avatar
Antoine Leca
En 40c0428a$0$13925$, Stephane Legras-Decussy va
escriure:
le C dit que un char fait au moins 8 bits (donc un prog portable ne
doit pas utiliser les autres bits)...


Pas directement, en effet.


cela me parait logique que les fonctions portables fputc()/fgetc() ne
voient que les 8 premiers bits des char... non ?


Non. Toujours avec les char sur 12 bits de Régis, suppose de plus que '3'
est codé 0x123 (donc '0' est 0x120, et '9' est 0x129). fputc('3', f) va bien
devoir écrire _au moins_ 9 bits, non ? Sinon comment fgetc() pourrait
fonctionner ?


Antoine

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Antoine Leca" wrote:

Les bytes des flux font toujours 8 bits (rien à voir avec le C).


En effet cela n'a rien à voir avec les flux ("streams") du C. Ceux-là
sont soit basés sur des char, soit basé sur des wchar_t (selon leur
orientation, cf fwide() et en général <wchar.h>).


Ok.

Un autre concept existant en C est celui de fichier associé au flux.
Ceux-ci peuvent parfaitement être basés sur des unités de taille plus
grandes ou plus petites. Un exemple clairement énoncé par la norme est
la possibilité d'avoir un flux élargi associé à un fichier de
"multibytes élargis" où le code 0 est possible sans signifier '', ce
qui suggère clairement la possibilité d'une implémentation de stdio qui
manipulent des fichiers textes encodés en UTF-16.


Huh! Il va valloir vite redéfinir Internet Protocol et ses flux de 8 bits. Va
y'avoir du sport!

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/


1 2 3 4