16

I have bit field declared this way:

typedef struct morder {
    unsigned int targetRegister : 3;
    unsigned int targetMethodOfAddressing : 3;
    unsigned int originRegister : 3;
    unsigned int originMethodOfAddressing : 3;
    unsigned int oCode : 4;
} bitset;

I also have int array, and I want to get int value from this array, that represents the actual value of this bit field (which is actually some kind of machine word that I have the parts of it, and I want the int representation of the whole word).

TylerH
  • 20,799
  • 66
  • 75
  • 101
Shahar Gvirtz
  • 2,418
  • 1
  • 14
  • 17
  • 3
    @shaharg: I think you're not quite precise with your language. The bit fields are the individual fields in your struct, but you seem to refer to the entire struct as a "bit field." – JXG Mar 18 '10 at 10:12

4 Answers4

28

Please, please, do not use a union. Or, rather, understand what you're doing by using a union--preferably before you use one.

As you can see in this answer, do not rely on bitfields to be portable. Specifically for your case, the ordering of the bitfields within a struct is implementation-dependent.

Now, if your question was, how can you print out the bitfield struct as an int, for occasional private review, sure, unions are great. But you seem to want the "actual value" of your bitfields.

So: if you only work on this one machine/compiler combination, and you don't need to rely on the mathematical value of the int, so long as it makes sense, you can use unions. But if you might port your code, or if you need the "actual value" of the int, you need to write bit-manipulation code to get the bit fields into the right int bits.

Community
  • 1
  • 1
JXG
  • 7,263
  • 7
  • 32
  • 63
  • 1
    Does implementation dependent mean compiler dependent, platform dependent, or both? – gsgx Jan 18 '13 at 02:53
  • 1
    @gsingh2011, both. A specific compiler for a specific architecture can do what it thinks is best. – JXG Jan 23 '13 at 08:51
  • 2
    @mahesh, not necessarily. The ordering is implementation-dependent, so the compiler can really do whatever it wants. There may be no mathematical meaning to the ordering. A union will give you a consistent mapping from bit fields to ints, but you don't know in advance if those ints will be the mathematical value. And if you port your code, every mapping may be different. – JXG Jan 16 '17 at 10:39
  • 2
    @Mahesh It is also worth noting that it is undefined behavior to read a member of a union that was not most recently written to. I think most compilers will do what you want, but something to keep in mind. – youngmit May 24 '17 at 14:57
  • @youngmit, it is not an undefined behavior since C99 with [Technical Corrigendum 3](https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm) applied. The result of such operation (reading from different union member) is _implementation defined_ and _may lead to_ undefined behavior if target member will contain trap representation as a result of such operation, but it's not an undefined behavior per se. – Alex Che Jul 01 '22 at 15:59
16

You can use a union:

typedef union bitsetConvertor {
    bitset bs;
    uint16_t i;
} bitsetConvertor;

bitsetConvertor convertor;
convertor.i = myInt;
bitset bs = convertor.bs;

Or you can use a cast:

bitset bs = *(bitset *)&myInt;

Or you can use an anonymous struct within a union:

typedef union morder {
    struct {
        unsigned int targetRegister : 3;
        unsigned int targetMethodOfAddressing : 3;
        unsigned int originRegister : 3;
        unsigned int originMethodOfAddressing : 3;
        unsigned int oCode : 4;
    };

    uint16_t intRepresentation;
} bitset;

bitset bs;
bs.intRepresentation = myInt;
Carl
  • 937
  • 10
  • 21
strager
  • 88,763
  • 26
  • 134
  • 176
  • 11
    Downvoted: `bitset bs = *(bitset *)&myInt;` is a classic example of breaking the *strict aliasing rule*. – user694733 Jun 28 '17 at 11:52
  • 5
    `uint16_t` is not guaranteed `unsigned int`. The union depends on implementation details; bitfield structs have hardly any guarantees about their layout. The cast violates the _effective type_ (aka strict aliasing) rule -> undefined behaviour. Bad approach. – too honest for this site Jun 28 '17 at 12:46
3

Just use a union. You can then access your data either as a 16 bit int or as individual bit-fields, e.g.

#include <stdio.h>
#include <stdint.h>

typedef struct {
    unsigned int targetRegister : 3;
    unsigned int targetMethodOfAddressing : 3;
    unsigned int originRegister : 3;
    unsigned int originMethodOfAddressing : 3;
    unsigned int oCode : 4;
} bitset;

typedef union {
    bitset b;
    uint16_t i;
} u_bitset;

int main(void)
{
    u_bitset u = {{0}};
    
    u.b.originRegister = 1;
    printf("u.i = %#x\n", u.i); 

    return 0;
}
Paul R
  • 208,748
  • 37
  • 389
  • 560
0

You can simply do

typedef struct morder {
  unsigned int targetRegister : 3;
  unsigned int targetMethodOfAddressing : 3;
  unsigned int originRegister : 3;
  unsigned int originMethodOfAddressing : 3;
  unsigned int oCode : 4;
} bitset;

short result;
std::memcpy(&result, &bitset, sizeof(short));

In this way, bitset's memory area will be copied inside a memory area and interpreted as a short.

result is a short because your bitset has size of 16bits (2bytes).

If you want a better way to set the memory size of the new buffer you can do (with c++11 or more)

std::memcpy(&result, &bitset, sizeof(decltype(result));

Another solution (very ugly and dangerous) is to reinterpret memory area:

short result = *reinterpret_cast<short*>(&bitset);
0xNIC
  • 135
  • 2
  • 10