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

champ de bits : pourquoi seulement ints ?

7 réponses
Avatar
rixed
Bonjour !

Je viens de découvrir avec étonnement que le type sous-jacent d'un champ
de bit ne pouvait être que int, unsigned int ou signed int. Je
m'attendait à ce que n'importe quel type entier soit autorisé.

Du coup, pas possible de faire des champs de bits avec plus de bits
qu'un int ?

Pas possible non plus, et c'est plus gênant pour moi, de reproduire un
motif de bit précis c'est à dire y compris sa taille ; je voulais en
effet avoir une série de valeurs 16 bits avec un motif bien particulier
comme ceci :

typedef struct {
uint16_t c:6;
uint16_t o:3;
uint16_t l:7;
} c_o_l;

c_o_l buffer[256];


Or ceci ne compile pas, et si je remplace les uint16_t par des unsigned
alors la taille de ma structure vaut alors sizeof(unsigned) (=4 ici) et
non plus sizeof(uint16_t) (=2 ici). Pas glop, pas glop ! Encore que ceci
soit peut être imputable au compilateur (gcc v3.et.des.poussières), que
rien n'oblige à gâcher tant de bits de la sorte (sauf peut être la
norme, qui sait ?).

Bon, en attendant vos lumières je me passerai de champs de bits.

7 réponses

Avatar
Pierre Maurette
Bonjour !

Je viens de découvrir avec étonnement que le type sous-jacent d'un champ
de bit ne pouvait être que int, unsigned int ou signed int. Je
m'attendait à ce que n'importe quel type entier soit autorisé.

Du coup, pas possible de faire des champs de bits avec plus de bits
qu'un int ?

Pas possible non plus, et c'est plus gênant pour moi, de reproduire un
motif de bit précis c'est à dire y compris sa taille ; je voulais en
effet avoir une série de valeurs 16 bits avec un motif bien particulier
comme ceci :

typedef struct {
uint16_t c:6;
uint16_t o:3;
uint16_t l:7;
} c_o_l;

c_o_l buffer[256];


Or ceci ne compile pas, et si je remplace les uint16_t par des unsigned
Êtes-vous certain de votre message d'erreur, que uint16_t est bien

défini sur votre machine ? C'est dans stdint.h, ou alors il faut par
exemple après vérifications dont le sizeof(short) faire un typedef.
Avez-vous vérifié que vous vous faites jeter avec des unsigned short ?

alors la taille de ma structure vaut alors sizeof(unsigned) (=4 ici) et
non plus sizeof(uint16_t) (=2 ici). Pas glop, pas glop ! Encore que ceci
soit peut être imputable au compilateur (gcc v3.et.des.poussières), que
rien n'oblige à gâcher tant de bits de la sorte (sauf peut être la
norme, qui sait ?).
Oui, la norme ne prévoit que des champs de type signed int, unsigned

int et éventuellement (C99) _Bool. Enfin, "or some other
implementation-defined type". Avec ça .... Elle laisse sauf erreur de
ma part l'implémentation choisir la taille utilisée pour stocker
l'ensemble des bitfields.
Dans la vraie vie, ça semble différent. En Win32 console, j'obtiens
2 2 512
sur le programme suivant avec 4 compilateurs (gcc 3.2 et 3.4.2, Borland
5.6.4 et VC++):


#include <stdio.h>
#include <stdint.h>

int main(void)
{
typedef struct
{
uint16_t c : 6;
uint16_t o : 3;
uint16_t l : 7;
}
c_o_l;

c_o_l buffer[256];

printf("%ut%ut%un", sizeof(uint16_t), sizeof(c_o_l), sizeof
buffer);

return 0;
}

On peut faire varier la taille des trois champs. On voit apparaître un
certain nombre de règles (à priori hors du champs du C portable). Je me
demande si ce ne sont pas celles de C++ ?


Bon, en attendant vos lumières je me passerai de champs de bits.
Vous pouvez en profiter pour affiner l'analyse de votre problème. Si la

taille du stockage est importante, stockez un tableau de uint16_t et
écrivez les opérations nécessaires (à priori des extractions vers un
type entier). Si c'est la vitesse et la portabilité, laissez faire le
compilateur. Peut-être ....

--
Pierre Maurette

Avatar
rixed
On 2005-11-24, Pierre Maurette wrote:
Or ceci ne compile pas, et si je remplace les uint16_t par des unsigned
Êtes-vous certain de votre message d'erreur, que uint16_t est bien

défini sur votre machine ?


Par "ça ne compile pas", il faut entendre que ça ne compile pas sans
que le compilateur n'emmette un soupçon d'avertissement :

"warning: bit-field `machin' type invalid in ISO C"

À par ça, il compile et produit le code attendu (c'est à dire celui que
vous avez vous-même obtenu).

Mais en bon lecteur assidus de f.c.l.c, je suis prêt à tous les
sacrifices pour faire taire un warning (surtout qu'avec colorgcc,
ca fait tâche).


Avatar
Targeur fou
rixed wrote:
Bonjour !


Bonjour,

Je viens de découvrir avec étonnement que le type sous-jacent d'un ch amp
de bit ne pouvait être que int, unsigned int ou signed int. Je
m'attendait à ce que n'importe quel type entier soit autorisé.


Oui, plus bool en C99 et une version qualifiée d'un de ces types.

Du coup, pas possible de faire des champs de bits avec plus de bits
qu'un int ?


Non, l'expression qui spécifie la largeur du membre champ de bits doit
être une expression entière constante et positive, inférieure ou
égale au nombre de bits qu'aurait un objet du type spécifié pour le
champ de bits.

ex:
struct
{
int champ :35; /* Hé ben pas bon si le int de ton implémentation
ne fait que 32 bits */
} s;


Pas possible non plus, et c'est plus gênant pour moi, de reproduire un
motif de bit précis c'est à dire y compris sa taille ; je voulais en
effet avoir une série de valeurs 16 bits avec un motif bien particulier
comme ceci :

typedef struct {
uint16_t c:6;
uint16_t o:3;
uint16_t l:7;
} c_o_l;

c_o_l buffer[256];


Or ceci ne compile pas, et si je remplace les uint16_t par des unsigned
alors la taille de ma structure vaut alors sizeof(unsigned) (=4 ici) et
non plus sizeof(uint16_t) (=2 ici).


C'est si gênant que ça, t'as des exigences pointues en terme de
mémoire !?

Une solution, uint16_t buffer[256] et des macros d'écriture et de
lecture par masques / décalages de bits, etc...

Pas glop, pas glop ! Encore que ceci
soit peut être imputable au compilateur (gcc v3.et.des.poussières), q ue
rien n'oblige à gâcher tant de bits de la sorte (sauf peut être la
norme, qui sait ?).

Bon, en attendant vos lumières je me passerai de champs de bits.


C'est bien mieux comme ça :-)

A+
Regis

Avatar
rixed
On 2005-11-24, Targeur fou wrote:
Or ceci ne compile pas, et si je remplace les uint16_t par des unsigned
alors la taille de ma structure vaut alors sizeof(unsigned) (=4 ici) et
non plus sizeof(uint16_t) (=2 ici).


C'est si gênant que ça, t'as des exigences pointues en terme de
mémoire !?


Oui, je doit construire un type pour représenter une succession de
motifs de 16 bits. Les masques de bits, ca n'a d'utilité que pour
construire des figures imposées (par le matériel), sinon ca ne sert à
rien du tout je pense. D'où mon étonnement initial.

Une solution, uint16_t buffer[256] et des macros d'écriture et de
lecture par masques / décalages de bits, etc...


Oui, c'est ce que j'ai fait.


Avatar
Antoine Leca
En news:, rixed va escriure:
Je viens de découvrir avec étonnement que le type sous-jacent d'un
champ de bit ne pouvait être que int, unsigned int ou signed int. Je
m'attendait à ce que n'importe quel type entier soit autorisé.


Drôle d'attente.


Du coup, pas possible de faire des champs de bits avec plus de bits
qu'un int ?


Pas de manière portable, non.

Et c'est assez logique : les champ de bits sont manipulés avec difficulté,
et il est très souvent impossible de faire des opérations directement en
mémoire, ce qui restreint aux opérations sur les registres.

Et historiquement, int est le type associé aux registres du processeur...


Pas possible non plus, et c'est plus gênant pour moi, de reproduire un
motif de bit précis c'est à dire y compris sa taille ;


C est d'abord un langage portable, il cherche donc à s'abstraire des
caractéristiques du processeur. Forcer une structure avec des champs de bits
à avoir une taille précise, c'est plutôt l'orientation opposée.


je voulais en effet avoir une série de valeurs 16 bits avec un motif
bien particulier comme ceci :


La solution portable va être d'en passer par des macros de masquage,
c'est-à-dire sans champ de bits.


typedef struct {
uint16_t c:6;
uint16_t o:3;
uint16_t l:7;
} c_o_l;

c_o_l buffer[256];


Or ceci ne compile pas,


Quel compilateur (précisement), quels entêtes avant, etc...

Pour info, cela compile ici, et cela donne même 512 octets comme tu le
désires.
Mais ce n'est pas portable.


Antoine

Avatar
Pierre Maurette
[...]
typedef struct {
uint16_t c:6;
uint16_t o:3;
uint16_t l:7;
} c_o_l;

c_o_l buffer[256];


Or ceci ne compile pas,


Quel compilateur (précisement), quels entêtes avant, etc...

Pour info, cela compile ici, et cela donne même 512 octets comme tu le
désires.
Comme signalé, ça compile et donne 512 sur 4 compilos sous Windows 32:

gcc 3.2, gcc 3.4 Borland 5.6 et Microsoft 14 et des brouettes
(VC++Express 2005), auxquels j'ajoute gcc 3.4.4 (Linux, AMD64).
rixed se plaint en fait d'un "avertissement". Je parlerais plutôt d'une
information, vu que -pedantic demande à signaler toute construction non
strictement ANSI C, et qu'il utilise une extension gcc. On ne peut pas
refaire la norme.
Bien entendu, ça compile sans warning en C++.


Mais ce n'est pas portable.
Peut-être le champ de portabilité recherché n'est-il pas universel ;-)

Peut-être rixed sait qu'il n'utilisera que gcc, peut-être ce que
représente la structure c_o_l n'est par essence pas portable. Sur mes
tests, j'ai toujours compilé et obtenu un sizeof buffer de 512, en
revanche j'ai eu à typedef-er le uint16_t.

En revanche, si je décidais d'utiliser les champs de bit sur des
uint16_t, et qu'il y avait du traitement massif sur le tableau, je
vérifierais auparavant qu'il n'y a pas perte de performances en
procédant ainsi. Il y a peut-être matière ici à optimiser au delà de ce
que ferait le compilateur.

--
Pierre Maurette


Avatar
Emmanuel Delahaye
Je viens de découvrir avec étonnement que le type sous-jacent d'un champ
de bit ne pouvait être que int, unsigned int ou signed int. Je


et bool (_Bool) en C99...

m'attendait à ce que n'importe quel type entier soit autorisé.

Du coup, pas possible de faire des champs de bits avec plus de bits
qu'un int ?


Le maximum garanti est 16-bit. Ca peut faire plus, mais ce n'est plus
garanti. La portablibilté est réduite, c'est tout.

Pas possible non plus, et c'est plus gênant pour moi, de reproduire un
motif de bit précis c'est à dire y compris sa taille ;


Les champs de bits, c'est pas fait pour faires des "constructions
précises" (mapping de registres matériel ou de champs de données de
flux), mais pour économiser de la place mémoire. Pour les "constructions
précises", il y a les opérateurs bits qui fonctionnent sur tous les
entiers non signés de façon portable.

http://mapage.noos.fr/emdel/clib/ed/inc/bits.h

--
A+

Emmanuel Delahaye