views:

277

answers:

5

Hey all,

First of all, I want to know if this is possible: let's say I have an unsigned long which contains some abritrary unsigned shorts, which may or may not be in the number. For example:

unsigned short int id1 = 3456,
                   id2 = 30998;

unsigned long long bitfld = id1|id2;

Can the other 2 fields be assumed as 0? And is OR the right operation for this? After that let's say I pass bitfld as an argument:

void dostuff (unsigned long long bf)
{
     //pseudo code
     if( the first field exists in bf)
         get first field;

     if( the second field exists in bf)
         get second field;

     //etc...
}

I think I have to poll out the first 16 bits of the bitfield and check those, then recursively poll them, verify them and store them if they are greater than 0. But I'm not sure how to do this, bit shifting only shifts left or right, thus, it only divides or multiplies right?

+4  A: 

short int is 2 bytes long, but long long is 8 bytes, so you have some kind of length mismatch; You may have meant this:

unsigned long long bitfld = id1|(id2<<16);

you can check is there is a field occupied by ANDing it like:

void dostuff (unsigned long long bf)
{
     //pseudo code
     if(bf & 0xFFFF)
         return bf & 0xFFFF;

     if(bf & 0xFF00)
         return (bf & 0xFFFF0000) >> 32;

 //etc...
}
alemjerus
In case of a short the bitmasks would have to be 0xffff and 0xffff0000 respectively, 0xff and 0xff00 only mask a single byte each.
x4u
The bits in the position must be cleared before using bitwise-OR. Otherwise a nice merge with previous bits occurs. Something that takes a long time to debug and find.
Thomas Matthews
A: 

Assuming unsigned short is 2 bytes and an unsigned long is 4 bytes.

unsigned short id1 = 0x0d80; //3456 decimal
unsigned short id2 = 0x7916; //30998 decimal
unsigned long bitfld = ((id2<<16)|id1)  //id2<<16 = 0x79160000, so bitfld = 0x79160d80
if ((bitfld & id1) == id1) {
    //id1 is in lower 2 bytes of bitfld
}
if ((bitfld>>16) &id2) == id2) { //bitfld>>16 = 0x00007916
    //id2 is in upper 2 bytes of bitfld
}

Does this help? When dealing with bits it's easier to visually see what is happening if you work with hex values.

tkyle
Masking long with the value could give unpredictable results
alemjerus
alemjerus - If you are concerned about the anding of the long and the short unsigned integer, then cast the shorts to longs.
tkyle
There are some nice operators and definitions that can be used without assuming bits per type: `sizeof()` and `CHAR_BIT`. The `sizeof` operator returns the size in *chars* and `CHAR_BIT` tells how many bits per *char*. Multiply and you get the number of bits:`bits = sizeof(int) * CHAR_BIT;`.
Thomas Matthews
+2  A: 

The bitwise OR operation is not what you want. The operation will merge existing bits with the new bits. You want an operation that replaces bits.

So first, you will need to clear out the bits using AND and NOT:

unsigned short int id1 = 3456,
                   id2 = 30998;

unsigned long long bitfld;

unsigned short int all_ones = ~0;
const unsigned int id2_position = 1;
const unsigned int bits_to_shift_left = id2_position * sizeof(unsigned short) * CHAR_BIT;
unsigned long long mask = ~(all_ones << bits_to_shift_left);
bitfld = bitfld & mask; // Erase all bits in id2 position
bitfld = bitfld | (id2 << bits_to_shift_left); // Put value into second position.

Unless lack of memory space is an issue, this kind of bit packing is not worth the development effort, validation time and extra execution time. Place the values into a "packed" buffer of unsigned char, then use the buffer with I/O.

Thomas Matthews
+1  A: 

You probably should review the bitshift operators and how they work. If you simply do: id1 | id2, you basically mashed all the bits together. You would not be able to extract these values individually later. What you wanted to do is something like id1 | (id2 << 16) as pointed out by the user alemjerus.

Another way of accomplishing the same goal without bitshitting is to use a union:


   struct s_btfld {
       unsigned short int f1;
       unsigned short int f2;
       unsigned short int f3;
       unsigned short int f4;
   };

   union u_btfld {
       struct s_btfld     fields;
       unsigned long long value;
   };

Now you can do:


   unsigned short int id1 = 3456, id2 = 30998;

   union u_btfld bitfld;

   bitfld.fields.f1 = id1;
   bitfld.fields.f2 = id2;

   dostuff(bitfld.value);

And in dostuff, you can easily retrieve the fields by:


   void dostuff(unsigned long long bf) {

      union u_btfld a;

      a.value = bf;

      printf("id1 = %d\n", a.fields.f1);
      printf("id2 = %d\n", a.fields.f2);

   }
figurassa
A: 

sorry for the bump. Thanks all for your answers, but I ended up using a simpler and more efficient method, an internal structure. You see, I could have done this easily with a string, but my purpose was transparency to the user of the code, easy to program so to say. I created an internal structure to hold my values and then a public method to create and return such structure, so it is easy to use and faster to parse (though it has the overhead of allocating in the stack a (albeit small) structure, which the bit field solution hasn't, but alas).

So thank you all for your answers.

Ricardo Ferreira