通过位操作将数据存储在变量中

时间:2022-06-25 16:58:57

I'm trying to store a date in an unsigned int variable, i need to store the date in this way:

我正在尝试将日期存储在unsigned int变量中,我需要以这种方式存储日期:

  • Bits 11 to 0 for the year (from 0 to 4095)
  • 年度比特11到0(从0到4095)

  • Bits 15 to 12 for the month (as if they were bits from 0 to 3, so i can store value from 0 to 11)
  • 本月的比特为15到12(好像它们是从0到3的位,所以我可以存储从0到11的值)

  • Bits 20 to 16 for the day (0-31)
  • 当天的比特20到16(0-31)

Storing the year it's not a problem, since i do this:

存储年份不是问题,因为我这样做:

unsigned int year=0;
year=year|2016

But then i have no idea i should put the month and the day. How can i put a number like 10 in the bits from 12 to 15 supposing bit 12 have value 1, bit 13 value 2 etc..

但后来我不知道我应该把月份和日期都放进去。如何将12中的数字设置为12到15,假设第12位的值为1,位13的值为2等。

Wich strategy should i use?

我应该使用哪种策略?

2 个解决方案

#1


3  

In C, you can shift bits both ways using a >> b or a << b where a is the number to shift and b is the number of shifts. The bits inserted will be 0s.

在C中,您可以使用>> b或a b来双向移位位,其中a是要移位的数字,b是移位的数量。插入的位将为0。

In your case, it would be

在你的情况下,它会

unsigned int time=0;
time |= year;
time |= month << 12;
time |= day << 16;

To unpack it, you simply have to shift time in the other direction and & it to the number of wanted bits:

要解压缩它,您只需将时间向另一个方向移动,并将其转换为所需的位数:

int year = time & 0b111111111111;
int month = (time >> 12) & 0b1111;
int day = (time >> 16) & 0b11111;

EDIT

If you want the data to be ordered from the most significant bit and stacked to it

如果您希望从最重要的位对数据进行排序并将其堆叠到其中

ex:

 11111111111111111111100000000000
 \___________|___|___/
      year  month day

you just need to shift the data accordingly

你只需要相应地移动数据

PACK:

short int_length = sizeof(unsigned int); //usually 32
unsigned int time=0;
time |= year << (int_length - 12);
time |= month << (int_length - 16);
time |= day << (int_length - 21);

UNPACK:

short int_length = sizeof(unsigned int); //usually 32
int year = (time >> (int_length - 12)) & 0b111111111111;
int month = (time >> (int_length - 16)) & 0b1111;
int day = (time >> (int_length - 21)) & 0b11111;

If you want the data to be ordered from the most significant bit and stacked to the least significant bit

如果您希望从最高有效位对数据进行排序并将其堆叠到最低有效位

ex:

 00000000000111111111111111111111
            \___________|___|___/
                  year  month day

Use instead this

请改用此

PACK:

unsigned int time=0;
time |= year << 9;
time |= month << 5;
time |= day;

UNPACK:

int year = (time >> 9) & 0b111111111111;
int month = (time >> 5) & 0b1111;
int day = time & 0b11111;

#2


0  

As others have mentioned, you may find a bitfield easier to work with than shifting and or'ing to align the bits. A bitfield is declared as a normal structure, but allows segregating bits between the members of the structure. For your year, month, day, you could use something similar to:

正如其他人所提到的,您可能会发现比使用移位和/或对齐位更容易使用位域。位域被声明为普通结构,但允许在结构的成员之间隔离位。对于您的年,月,日,您可以使用类似于:

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

The datebits struct segregates the first 11 bits for the year, the next 4 for the month, and the final 4 for the day. You use it just like any other struct. Here is a short example:

datebits结构分离了年份的前11位,下一个月份的4位,以及当天的最后4位。您可以像使用任何其他结构一样使用它。这是一个简短的例子:

#include <stdio.h>

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

typedef union {     /* union to avoid violating strict aliasing    */
    datebits d;     /* when shifting datebits to print binary bits */
    unsigned u;     /* (this is only for putchar bit output)       */
} duu;

int main (void) {

    unsigned i = 19;
    datebits d;     /* declare bitfield */
    duu du;

    d.year = 1999;  /* fill bitfield */
    d.mon  = 12;
    d.day  = 2;

    du.d = d;

    printf ("\n year : %u  month : %u  day : %u\n\n (bits in memory) d : ",
            d.year, d.mon, d.day);

    while (i--)     /* verification of each bit in memory */
        putchar ((du.u >> i) & 1 ? '1' : '0');
    putchar ('\n');

    return 0;
}

Output

$ ./bin/bitfield_datebits

 year : 1999  month : 12  day : 2

 (bits in memory) d : 0010110011111001111

(note: the union is just to facilitate the binary printing of the individual bits, it is not needed for normal use of datebits).

(注意:联合只是为了方便二进制打印各个位,正常使用datebits不需要它)。

As you can see your day is 0010, your month 1100 and the year 11111001111 in proper order.

正如您所看到的那样,您的一天是0010,您的月份是1100,年份是11111001111。

#1


3  

In C, you can shift bits both ways using a >> b or a << b where a is the number to shift and b is the number of shifts. The bits inserted will be 0s.

在C中,您可以使用>> b或a b来双向移位位,其中a是要移位的数字,b是移位的数量。插入的位将为0。

In your case, it would be

在你的情况下,它会

unsigned int time=0;
time |= year;
time |= month << 12;
time |= day << 16;

To unpack it, you simply have to shift time in the other direction and & it to the number of wanted bits:

要解压缩它,您只需将时间向另一个方向移动,并将其转换为所需的位数:

int year = time & 0b111111111111;
int month = (time >> 12) & 0b1111;
int day = (time >> 16) & 0b11111;

EDIT

If you want the data to be ordered from the most significant bit and stacked to it

如果您希望从最重要的位对数据进行排序并将其堆叠到其中

ex:

 11111111111111111111100000000000
 \___________|___|___/
      year  month day

you just need to shift the data accordingly

你只需要相应地移动数据

PACK:

short int_length = sizeof(unsigned int); //usually 32
unsigned int time=0;
time |= year << (int_length - 12);
time |= month << (int_length - 16);
time |= day << (int_length - 21);

UNPACK:

short int_length = sizeof(unsigned int); //usually 32
int year = (time >> (int_length - 12)) & 0b111111111111;
int month = (time >> (int_length - 16)) & 0b1111;
int day = (time >> (int_length - 21)) & 0b11111;

If you want the data to be ordered from the most significant bit and stacked to the least significant bit

如果您希望从最高有效位对数据进行排序并将其堆叠到最低有效位

ex:

 00000000000111111111111111111111
            \___________|___|___/
                  year  month day

Use instead this

请改用此

PACK:

unsigned int time=0;
time |= year << 9;
time |= month << 5;
time |= day;

UNPACK:

int year = (time >> 9) & 0b111111111111;
int month = (time >> 5) & 0b1111;
int day = time & 0b11111;

#2


0  

As others have mentioned, you may find a bitfield easier to work with than shifting and or'ing to align the bits. A bitfield is declared as a normal structure, but allows segregating bits between the members of the structure. For your year, month, day, you could use something similar to:

正如其他人所提到的,您可能会发现比使用移位和/或对齐位更容易使用位域。位域被声明为普通结构,但允许在结构的成员之间隔离位。对于您的年,月,日,您可以使用类似于:

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

The datebits struct segregates the first 11 bits for the year, the next 4 for the month, and the final 4 for the day. You use it just like any other struct. Here is a short example:

datebits结构分离了年份的前11位,下一个月份的4位,以及当天的最后4位。您可以像使用任何其他结构一样使用它。这是一个简短的例子:

#include <stdio.h>

typedef struct {    /* bitfield for year, month, day */
    unsigned    year : 11,
                mon  :  4,
                day  :  4;
} datebits;

typedef union {     /* union to avoid violating strict aliasing    */
    datebits d;     /* when shifting datebits to print binary bits */
    unsigned u;     /* (this is only for putchar bit output)       */
} duu;

int main (void) {

    unsigned i = 19;
    datebits d;     /* declare bitfield */
    duu du;

    d.year = 1999;  /* fill bitfield */
    d.mon  = 12;
    d.day  = 2;

    du.d = d;

    printf ("\n year : %u  month : %u  day : %u\n\n (bits in memory) d : ",
            d.year, d.mon, d.day);

    while (i--)     /* verification of each bit in memory */
        putchar ((du.u >> i) & 1 ? '1' : '0');
    putchar ('\n');

    return 0;
}

Output

$ ./bin/bitfield_datebits

 year : 1999  month : 12  day : 2

 (bits in memory) d : 0010110011111001111

(note: the union is just to facilitate the binary printing of the individual bits, it is not needed for normal use of datebits).

(注意:联合只是为了方便二进制打印各个位,正常使用datebits不需要它)。

As you can see your day is 0010, your month 1100 and the year 11111001111 in proper order.

正如您所看到的那样,您的一天是0010,您的月份是1100,年份是11111001111。