3

I wanted to implement LFSR(linear feedback shift registers) in C to generate random bits. When I try to modify an individual bit or just assign a short value to memory block, all the bits set to 1. How can I stop this from happening?

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
}
timrau
  • 22,578
  • 4
  • 51
  • 64
Grey
  • 133
  • 4
  • Don't use `htons()`, that doesn't make sense. – Marco Bonelli Aug 30 '19 at 10:16
  • 2
    why a `union` for your bit field? I would use a `struct`. – prog-fh Aug 30 '19 at 10:20
  • @prog-fh I will use a 16 bit key value, then i have to access each bit of the key. – Grey Aug 30 '19 at 10:23
  • @MarcoBonelli Why? The algorithm is using big endian byte order for key. – Grey Aug 30 '19 at 10:33
  • @Grey oh, ok, maybe should have specified that in the question then. – Marco Bonelli Aug 30 '19 at 10:37
  • 1
    Please be warned that using unions is not a very portable way to perform this kind of computation. It becomes highly implementation-dependent. It is better to use bit-wise operators on a variable of the appropriate type, say a `uint16_t` rather than bit-fields if you don't want any surprises when you change your compiler or platform! – th33lf Aug 30 '19 at 11:35
  • 1
    @th33lf *It is better to use bit-wise operators ... if you don't want any surprises ...* It's not only better, it's [completely and totally **necessary**](https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p11): *If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is **implementation-defined**. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is **implementation-defined**. The alignment of the addressable storage unit is **unspecified**.* – Andrew Henle Aug 30 '19 at 13:31
  • @Grey *The algorithm is using big endian byte order for key.* if you require a specific bit order, you **can't** use bit-fields in portable code. Different compilers on the same platform are allowed to implement them differently. – Andrew Henle Aug 30 '19 at 13:33
  • Union doesn't make any sense. But ignoring that, the only time you will get endianess problems is when you use bitfields. If you have been sensible to use a raw `uint16_t` together with shifts, endianess wouldn't be a problem and everything would be 100% portable. Shifts are also known to generate the fastest possible machine code. This would be why every solution not using bit shifts is highly questionable. – Lundin Aug 30 '19 at 13:39

3 Answers3

8

The problem is that the union means that each and every one of the one-bit bitfield members access the exact same one bit. What you want to do is

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

    unsigned short ff;
};
4

You are probably understanding the union differently. All the bit-fields are aliased at the same location. You probably want to do something like this:

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

You can have a look here about differences between a struct and a union.

Update:
As per the comments @the-busybee regarding the alignment of bit-fields based on architecture is also worth noting regarding portability of the code across various architectures.
Refer answers here regarding the discussion on bit endianess.

AmeyaVS
  • 814
  • 10
  • 26
3

When you declare an Union, all elements of Unions are part of same memory. They are just accessed differently.

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

Here, ff_0 and ff_1 are same memory and so is ff That is why, when you assign a value to ff_0, it automatically assigned to ff_1. So what you are observing is correct.

What you should do is, create a structure with 15 bit fields. Then union should be struct and unsigned short.

Swanand
  • 4,027
  • 10
  • 41
  • 69