0

Now I have a struct looking like this:

struct Struct {
    uint8_t val1 : 2;
    uint8_t val2 : 2;
    uint8_t val3 : 2;
    uint8_t val4 : 2;
} __attribute__((packed));

Is there a way to make all the vals a single array? The point is not space taken, but the location of all the values: I need them to be in memory without padding, and each occupying 2 bits. It's not important to have array, any other data structure with simple access by index will be ok, and not matter if it's plain C or C++. Read/write performance is important - it should be same (similar to) as simple bit operations, which are used now for indexed access.

Update:

What I want exactly can be described as

struct Struct {
    uint8_t val[4] : 2;
} __attribute__((packed));
aplavin
  • 2,199
  • 5
  • 32
  • 53
  • I removed my answer (array of structs) because it did not meet one of your main criteria: _Read/write performance is important - it should be same (similar to) as simple bit operations, which are used now for indexed access_ An array of struct would not provide contiguous memory locations for the array elements of that struct, and that would degrade Read/Write performance. So far then, I believe MadScienceDreams (although a weird moniker :) has offered the concept most closely matching your stated goal. – ryyker Feb 10 '14 at 17:32

2 Answers2

1

No, C only supports bitfields as structure members, and you cannot have arrays of them. I don't think you can do:

struct twobit {
    uint8_t val : 2;
} __attribute__((packed));

and then do:

struct twobit array[32];

and expect array to consist of 32 2-bit integers, i.e. 8 bytes. A single char in memory cannot contain parts of different structs, I think. I don't have the paragraph and verse handy right now though.

You're going to have to do it yourself, typically using macros and/or inline functions to do the indexing.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • I don't mean a separate array of such types, but a field in a structure, with this field being an array. – aplavin Feb 10 '14 at 16:28
0

You have to manually do the bit stuff that's going on right now:

constexpr uint8_t get_mask(const uint8_t n)
{
  return ~(((uint8_t)0x3)<<(2*n));
}

struct Struct2
{
  uint8_t val;

  inline void set_val(uint8_t v,uint8_t n)
  {
    val = (val&get_mask(n))|(v<<(2*n));
  }

  inline uint8_t get_val(uint8_t n)
  {
    return (val&~get_mask(n))>>(2*n);
  }

  //note, return type only, assignment WONT work.
  inline uint8_t operator[](uint8_t n)
  {
    return get_val(n);
  }
};

Note that you may be able to get better performance if you use actual assembly commands.

Also note that, (almost) no matter what, a uint8_t [4] will have better performance than this, and a processor aligned type (uint32_t) may have even better performance.

IdeaHat
  • 7,641
  • 1
  • 22
  • 53