3
votes

Je ne peux pas manipuler les champs de bits en C

Je voulais implémenter LFSR (registres à décalage à rétroaction linéaire) en C pour générer des bits aléatoires. Lorsque j'essaye de modifier un bit individuel ou simplement d'attribuer une valeur courte au bloc de mémoire, tous les bits sont mis à 1. Comment puis-je empêcher cela?

struct lfsr{
    //... 
    union{
        unsigned short ff_0 : 1;
        unsigned short ff_1 : 1;
        //... 
        unsigned short ff_f : 1;
        unsigned short ff;
    }flip_flops;
};

int main() {
    struct lfsr gen;
    gen.flip_flops.ff = 1;      //all the ff's set to 1
    gen.flip_flops.ff = htons(0x0001);//all the ff's set to 1
    gen.flip_flops.f_0 = 1;     //all the ff's set to 1
    gen.flip_flops.f_0 = 0;     //all the ff's set to 0
}


9 commentaires

N'utilisez pas htons () , cela n'a aucun sens.


pourquoi une union pour votre champ de bits? J'utiliserais une struct .


@ prog-fh J'utiliserai une valeur de clé de 16 bits, puis je devrai accéder à chaque bit de la clé.


@MarcoBonelli Pourquoi? L'algorithme utilise l'ordre des octets big endian pour la clé.


@Grey oh, ok, peut-être aurait-il dû le préciser dans la question.


Veuillez noter que l'utilisation des unions n'est pas une manière très portable d'effectuer ce type de calcul. Cela devient fortement dépendant de la mise en œuvre. Il est préférable d'utiliser des opérateurs binaires sur une variable du type approprié, disons un uint16_t plutôt que des champs binaires si vous ne voulez pas de surprises lorsque vous changez de compilateur ou de plateforme!


@ th33lf Il vaut mieux utiliser des opérateurs bit par bit ... si vous ne voulez pas de surprises ... Ce n'est pas seulement mieux, c'est complètement et totalement nécessaire : S'il reste un espace insuffisant, si un Le champ de bits qui ne rentre pas est placé dans l'unité suivante ou chevauche des unités adjacentes est défini par l'implémentation . L'ordre d'allocation des champs de bits au sein d'une unité (d'ordre élevé à bas ou d'ordre inférieur à élevé) est défini par l'implémentation . L'alignement de l'unité de stockage adressable est non spécifié .


@Grey L'algorithme utilise un ordre d'octets gros boutiste pour la clé. si vous avez besoin d'un ordre de bits spécifique, vous ne pouvez pas utiliser des champs de bits dans le code portable. Différents compilateurs sur la même plate-forme sont autorisés à les implémenter différemment.


L'union n'a aucun sens. Mais en ignorant cela, le seul moment où vous aurez des problèmes d'endianess est lorsque vous utilisez des champs de bits. Si vous avez été judicieux d'utiliser un uint16_t brut avec des changements, l'endianess ne serait pas un problème et tout serait 100% portable. Les décalages sont également connus pour générer le code machine le plus rapide possible. C'est pourquoi toute solution n'utilisant pas de décalage de bits est hautement discutable.


3 Réponses :


8
votes

Le problème est que l'union signifie que chacun des membres du champ de bits d'un bit accède exactement au même bit. Ce que vous voulez faire est

union lfsr{
    //... 
    struct {
        unsigned short ff_0 : 1;
        unsigned short ff_1 : 1;
        //... 
        unsigned short ff_f : 1;
    }flip_flops;

    unsigned short ff;
};


2 commentaires

Ce que vous voulez faire, c'est ... Eh bien, sauf pour le fait que les champs de bits ne sont absolument pas portables et qu'il n'y a pas de mappage cohérent et portable de l'un des champs de bits avec les bits réels du < code> short ff non signé membre du syndicat.


Cela va sans dire mais au moins cela fonctionnerait sur certaines implémentations au lieu de 0



4
votes

Vous comprenez probablement le syndicat différemment. Tous les champs de bits sont aliasés au même emplacement. Vous voudrez probablement faire quelque chose comme ceci:

struct lfsr{
  //... 
  union{
    struct {
      unsigned short ff_0 : 1;
      unsigned short ff_1 : 1;
      //... 
      unsigned short ff_f : 1;
    };
    unsigned short ff;
  }flip_flops;
};

Vous pouvez jeter un œil ici sur les différences entre une structure et une union.

Mise à jour:
Selon les commentaires @ the-busybee concernant l'alignement des champs de bits basés sur l'architecture, il convient également de noter la portabilité du code à travers diverses architectures.
Reportez-vous aux réponses ici concernant la discussion sur le bit endianess. p>


2 commentaires

Merci beaucoup, je pensais que le syndicat ne pouvait pas affecter les champs de bits.


Soyez conscient de la finalité et des positions des bits dans ff ! Ce n'est peut-être pas ce à quoi vous vous attendez.



3
votes

Lorsque vous déclarez une Union, tous les éléments des Unions font partie de la même mémoire. On y accède simplement différemment.

 union{
        unsigned short ff_0 : 1;
        unsigned short ff_1 : 1;
        //... 
        unsigned short ff_f : 1;
        unsigned short ff;
    }flip_flops;

Ici, ff_0 et ff_1 sont la même mémoire, tout comme ff C'est pourquoi, lorsque vous attribuez une valeur à ff_0, elle est automatiquement affectée à ff_1. Donc ce que vous observez est correct.

Ce que vous devez faire est de créer une structure avec des champs de 15 bits. Alors union devrait être struct et unsigned short.


0 commentaires