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

Portabilite d'un typecast (unsigned int) sur un bitfield

3 réponses
Avatar
Lea GRIS
Bonjour,

J'effectue des test en utilisant une table de vérités encodée dans un
tableau dans le but d'apporter une solution générique en remplacement de
conditions imbriquées. (Autre avantage : La matrice est re-définissable
à l'exécution.)

Il s'agit de mettre en correspondance les valeurs booléennes en entrée
contenues dans un champ de bits et de les combiner pour indexer l'action
ou la valeur résultante.

Cependant pour indexer le tableau de vérités, le champ de bit contenant
les valeurs booléennes doit être considéré comme valeur entière composée
de tous les bits du champ.

J'aimerais savoir si c'est une construction acceptable _et surtout
portable_ d'utiliser un "typecast (unsigned int)" sur un champ de bits.

Selon les architectures CPU/compilateur, cette redéfinition de type
"bitfiled" vers "unsigned int" restera-t'elle cohérente (petit indien,
grand indien) ?

Voici un extrait de code correspondant :

/* champ de 4 bits contenant les états booléens en entrée */
struct issue_flags
{
bool issue_ended : 1;
bool ticket_ended : 1;
bool hold_started : 1;
bool hold_ended : 1:
};

/* énumération des états résultants */
enum issue_states
{
OK, PENDING, HOLD, CANCELED, UNDEFINED
};

/* Table de vérités mettant en relation
* les états en entrée avec les valeurs résultantes.
*/
const enum issue_states truths[] =
{ PENDING, OK, OK, OK, HOLD, CANCELED, CANCELED, CANCELED, UNDEFINED,
UNDEFINED, UNDEFINED, UNDEFINED, HOLD, OK, OK, OK
};

/* Labels correspondants aux états résultants */
const char *states_labels[] =
{ "OK", "Pending", "Hold", "Canceled", "Undefined" };

/* Restitution du label correspondant à l'état d'entrée
* contenu dans le champ de bits flags
*/
const char *
do_test (issue_flags flags)
{
unsigned int state; /* état résultant */

/* flags étant de type champ de bits issue_flags,
* Il a besoin d'être considéré comme nombre entier
* pour servir d'index à la table de vérités.
*/
state = truths[(unsigned int)flags];
return (states_labels[state]);
}

--
Léa Gris

3 réponses

Avatar
Jean-Marc Bourguet
Lea GRIS writes:

J'aimerais savoir si c'est une construction acceptable _et surtout
portable_ d'utiliser un "typecast (unsigned int)" sur un champ de bits.


Non.

struct issue_flags
{
bool issue_ended : 1;
bool ticket_ended : 1;
bool hold_started : 1;
bool hold_ended : 1:
};
...

const char *
do_test (issue_flags flags)
...

state = truths[(unsigned int)flags];
...


--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Antoine Leca
En news:47947c46$0$880$, Lea GRIS va escriure:
J'aimerais savoir si c'est une construction acceptable _et surtout
portable_ d'utiliser un "typecast (unsigned int)" sur un champ de
bits.


Non.


Selon les architectures CPU/compilateur, cette redéfinition de type
"bitfiled" vers "unsigned int" restera-t'elle cohérente (petit indien,
grand indien) ?


Pas du tout.
En plus de petit- ou grand-boutien pour les entiers, tu dois considérer la
possibilité que les bits (et donc les champs de bits) soit numérotés de
gauche à droite ou de droite à gauche (ce qui dépend du compilateur), et
aussi de savoir si le remplissage au-delà des 4 bits que tu définis soit par
la gauche ou par la droite (ce qui dépend souvent de l'architecture cible et
des possibilités qu'elle offre, et donc de la vision qu'en a celui qui écrit
le compilateur).
Le tout devra être rangé dans un entier (de 16 ou de 32 bits ? ah non, de
64...)


Voici un extrait de code correspondant :

/* champ de 4 bits contenant les états booléens en entrée */
struct issue_flags
{
bool issue_ended : 1;


bool est C99 (ou C++). Si tu utilises un compilateur C90, en général on
utilise
typedef int bool;
ou quelque chose du même genre; et il est alors possible que le compilateur
interprète le tout comme la déclaration d'un champ de UN bit de type ENTIER
(signé), donc pouvant contenir 0 ou... -1

Bref, en règle général si tu souhaites faire quelque chose de portable, il
ne faut pas utiliser les champs de bits.

Tu auras un résultat largement plus portable et aussi lisible avec un truc
du genre

enum issue_flags {
issue_ended = 1,
ticket_ended = issue_ended<<1,
hold_started = ticket_ended<<1,
hold_ended = hold_started<<1 };

et l'utilisation des opérateurs & (tester un indicateur), |= (le
positionner), &= ~ (l'effacer) et ^= (l'inverser), ce qui revient à
contrôler toi-même les opérations sur le champ de bits.


Antoine

Avatar
Lea GRIS

Bref, en règle général si tu souhaites faire quelque chose de portable, il
ne faut pas utiliser les champs de bits.

Tu auras un résultat largement plus portable et aussi lisible avec un truc
du genre

enum issue_flags {
issue_ended = 1,
ticket_ended = issue_ended<<1,
hold_started = ticket_ended<<1,
hold_ended = hold_started<<1 };

et l'utilisation des opérateurs & (tester un indicateur), |= (le
positionner), &= ~ (l'effacer) et ^= (l'inverser), ce qui revient à
contrôler toi-même les opérations sur le champ de bits.


Merci Antoine pour l'explication claire et détaillée. Je vais étudier et
utiliser tout ça avec mon code.

--
Léa Gris