Assigning a value bit by bit
If I have a struct like so:
struct example
{
uint16_t bar:1;
uint16_t foo:1;
};
Then I have another 16-bit variable: uint16_t value;
If I want the first bit in "value" to be assigned to "example.bar", and the second bit in value to be assigned to "example.foo", how would I do that?
EDIT:
I tried the following:
typedef struct
{
unsigned short in_1_16;
unsigned short in_17_32;
unsigned short in_33_48;
} READSTR;
typedef struct
{
unsigned short chan_1_16;
unsigned short chan_17_32;
unsigned short chan_33_48;
} TLM;
void main()
{
TLM tlm;
tlm.chan_1_16 = 0xFFFF;
READSTR t675;
t6开发者_开发知识库75.in_1_16 = 0x10;
t675.in_17_32 = 0x9;
t675.in_33_48 = 0x8;
tlm.chan_1_16 |= t675.in_1_16 & 1;
tlm.chan_1_16 |= t675.in_1_16 & (1 << 1);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 2);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 3);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 4);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 5);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 6);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 7);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 8);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 9);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 10);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 11);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 12);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 13);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 14);
tlm.chan_1_16 |= t675.in_1_16 & (1 << 15);
printf("%x", tlm.chan_1_16);
So I am setting the value in on struct to all ones (0xFFFF), and I am trying to set it to 0x10, bit by bit. But when I run this code I still get 0xFFFF. Not sure what I am doing wrong?
It is impossible to tell, because bit fields are very poorly defined by the standard. The following, you cannot know:
- whether bit field int is treated as signed or unsigned int
- the bit order (lsb is where?)
- whether the bit field can reach past the memory alignment of the CPU or not
- the alignment of non-bit field members of the struct
- the memory alignment of bit fields (to the left or to the right?)
- the endianess of bit fields
- whether plain int values assigned to them are interpreted as signed or unsigned
- how bit fields are promoted implicitly by the integer promotions
- whether signed bit fields are one’s complement or two’s complement
- location of padding bytes
- how padding bits are treated
- values of padding bits
- and so on
As you hopefully can tell, bit fields are very very bad and shouldn't be used ever. The only sensible solution is to re-write the code without bit fields:
#define FOO 0x01U
#define BAR 0x02U
uint16_t value;
value |= FOO; /* set FOO bit */
value &= ~FOO; /* clear FOO bit */
The above code can be executed on any C/C++ compiler for any system in the world and you will get the expected result.
#include <iostream>
typedef unsigned short uint16;
struct example
{
uint16 bar:1;
uint16 foo:1;
};
union foo
{
struct example x;
uint16 value;
};
int main()
{
uint16 bar = 0x01;
foo f;
f.value = bar;
std::cout << f.x.bar << std::endl; // display 1
std::cout << f.x.foo << std::endl; // display 0
}
EDIT
This snippet was used in production code and it used to work as intended. Anyway, it was tested with static assert and unit-tests that guaranteed its correctness. Since they're not reported here, I agree it should not be used "as is".
Since you (the OP) mentioned C++, I suggest to use std::bitset
class:
#include <bitset>
int main()
{
std::bitset<16> set(bar);
example x;
x.bar = set[0];
x.foo = set[1];
std::cout << x.bar << std::endl; // display 1
std::cout << x.foo << std::endl; // display 0
}
try it with:
struct example x;
x.bar = value & 1;
x.foo = value & 1 << 1;
fooN = value & 1 << N;
Values assigned to unsigned bitfields are defined to be reduced modulo 2**N, where N is the number of bits in the bitfield. This means that if you assign an unsigned number to an unsigned bitfield, the least significant N bits of the original number will be used.
So, given struct example x
, if you want the least significant bit of value
to be placed in x.bar
you can simply do:
x.bar = value;
If you want the second-least-significant bit of value
to be placed in x.foo
, you can likewise use:
x.foo = value >> 1;
精彩评论