1

I need to use a 6-byte (48-bit) bitfield in a structure that I can use as unsigned integer for comparison etc. Something along the following:

pack (1)
struct my_struct {
  _int64 var1:48;
} s;

if (s.var >= 0xaabbccddee) { // do something }

But somehow on 64-bit Windows, sizeof this struct always returns 8 bytes instead of 6 bytes. Any pointers are appreciated?

phuclv
  • 37,963
  • 15
  • 156
  • 475
cool.2k7
  • 21
  • 1
  • 2
  • 1
    What happens if you use a type other than `_int64`, such as `int`? The compiler is within its rights to decide that the structure must be 4-byte or 8-byte aligned (rather than 2-byte aligned). Packing is just a hint to the compiler. – Jonathan Leffler Mar 06 '12 at 06:39

3 Answers3

3

You have used _int64 and hence sizeof returns 8. Its like you've decided to use up 48 bits out of the available 64 bits. Even if we declare something like this-

struct my_struct {
  _int64 var1:1;
} s;

Still sizeof would say 8. In short, allocation of bitfields would take place according to the type of the bitfield. In this case its _int64 and hence 8 bytes allocation.

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
  • Thanks Pavan. Is there a way to use a 48 bit # so that I can perform basic operations on the field like +, -, >, < etc just like I would do on a _int64 ? – cool.2k7 Mar 06 '12 at 06:57
  • If you see this-http://msdn.microsoft.com/en-us/library/aa261215(v=vs.60).aspx, you can create a 64-bit **unsigned integer** bitfield type too and use it. You can perform all basic operations just like normal. You don't need to bother about the unused 16 bits! – Pavan Manjunath Mar 06 '12 at 07:19
  • I understand that part, but I need to have a structure (or a type) that consumes only 48 bits but semantically can be used just like _int64 for basic operations. ??? – cool.2k7 Mar 06 '12 at 15:33
  • Can I know what is the that which imposing such a stringent requirement? So that we can think of alternatives? Which is of more concern to you? Speed or ease of use? – Pavan Manjunath Mar 06 '12 at 15:52
  • sure. my struct represents a protocol packet which has a 48 bit field and hence the space requirement. the field requires some basic operations like >=, +, - etc which needs to be completed no slower than for a normal _int64 and hence the requirement to be used as _int64 for basic operations. Thanks. – cool.2k7 Mar 06 '12 at 16:29
  • also I have a existing large code base which has the same field as 32-bit and now I want to change this field to 48-bit without changing the rest of the code which performs operations on this field. – cool.2k7 Mar 06 '12 at 17:09
2

Unfortunately, a bit filed have the size of the underlying type, in this case an _int64 is 8 bytes.

As there is no six byte integers in any compiler that I know of, you would have to find a better way. One is to use one 16 and one 32 bit value (or three 16 bit values) and write your own comparison function.

For example:

struct my_struct
{
  uint16_t high;
  uint32_t low 
} s;

if (   (s.high > 0xaa)
    || (   (s.high == 0xaa)
        && (s.low >= 0xbbccddee)))
{ ... do something ... }

As a bonus you don't need #pragma pack, which brings a lot of other problems.

Lindydancer
  • 25,428
  • 4
  • 49
  • 68
  • 2
    On many systems, that structure will be an 8-byte unit, with 2 bytes of padding between `high` and `low`. – Jonathan Leffler Mar 06 '12 at 06:45
  • Thank you for your response. This is exactly what I want to avoid to perform multiple comparison when I know a _int64 can be compared in on comparison. – cool.2k7 Mar 06 '12 at 06:48
  • You are right. However if you use an array of three 16-bit values, as I also suggested In the answer, you should be ok. The comparison expression will be somewhat more complex, though. – Lindydancer Mar 06 '12 at 07:54
-1

I did some google search. Found out you might be able to use __attribute__((packed)).

http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html

  24 typedef struct __uint48_t uint48_t;                                             
  25 struct __attribute__((packed)) __uint48_t {                                     
  26     uint64_t _m:48;                                                             
  27 };      

 29 void test()                                                                     
 30 {                                                                               
 31     uint48_t a;                                                                 
 32     a._m = 281474976710655;                                                     
 33     printf("%llu", a._m);                                     
 34     printf("%u", sizeof(a));                                                  
 35                                                                                 
 36     a._m = 281474976710656;                                                     
 37     printf("%llu", a._m);                                                     
 38 }                   

 main1.c: In function ‘test’:
 main1.c:36:2: warning: large integer implicitly truncated to unsigned type [-Woverflow]

 $ ./a.out 
 281474976710655
 6
 0

But, as you said you are using Windows, which might be different.

I could be wrong, if so just point it out.

BTW, I still do not know what is the best solution to this question. Using struct makes thing a little awkward (you need call a._m instead of a, could we get round with it?) But at least it seems safer than just using uint64_t.

phuclv
  • 37,963
  • 15
  • 156
  • 475
randomness2077
  • 1,119
  • 2
  • 13
  • 25
  • `packed` only controls whether padding can be inserted between aligned members. It does not allow members to become misaligned. The underlying type of the bitfield is `uint64_t`, so it still requires 8 bytes of alignment. – underscore_d Jan 05 '16 at 13:10
  • note that [the result of `sizeof` must be printed using `%zu`](https://stackoverflow.com/q/940087/995714) – phuclv Aug 08 '19 at 12:42