如何将 signed int 转换为 15 位位域?

How to cast signed int to 15 bit bit-field?

我有一些位域:

int somefield : 15;

我正在尝试将 int 转换为 15 位(可以是正数或负数)。

有效执行此操作的最佳做​​法是什么?

I'm trying to convert an int to 15 bit (can be positive or negative). What is the best practice to do it efficiently?

如果要转换的int是15位有符号整数范围内的,简单使用下面的代码。重要的是不要在没有 signed 的情况下使用 int 来定义位域,因为这是 C 规范中的一个地方,它有所不同。如果没有 signedint 位域可以实现为 unsigned。它是实现定义的。

signed int somefield:15;
...
x.somefield = 12345;
int y = x.somefield;

如果要转换的 int 可能超出 15 位有符号整数的范围,最好使用 unsigned 字段以具有可移植一致的定义行为。当 int 超出范围时,OP 想要存储什么值尚不清楚。如果需要恢复标志,可能需要一些额外的代码。根据编码需要,没有额外的写入开销和读取开销。

unsigned somefield:15;
...
x.somefield = 123456;

x.somefield = -1;
int y = x.somefield >= 0x4000 ? x.somefield - 0x8000 : x.somefield;

或者,如果要分配的值可能超出位域范围,请确保分配不会发生。额外的写入开销和 none 读取开销。

signed int somefield 15;
...
if (i >= INT15_MIN && i <= INT15_MAX) x.somefield = i;
else TBD();

int y = x.somefield;

chux,非常感谢! 我找到了另一种选择,它看起来也很简单:

typedef struct {
    unsigned int firstletter: 5;
    unsigned int secondletter: 5;
    unsigned int thirdletter: 5;
  } data_in_32_format;

typedef struct {
    unsigned int somedata: 15;
  } data;

typedef union {
    data_in_32_format;
    data;
  } common_data;

因此,当我自己写入数据时,我正在写入:

common_data entry;
entry.data = getint_in_decimal_format;

比起我以 32 格式打印:

print32("%c%c%c\n", entry.data_in_32_format.thirdletter
                  , entry.data_in_32_format.secondletter
                  , entry.data_in_32_format.firstletter);

因为我需要在之前将其正确转换为 char(0-9 => 数字,>9 - 字母,所以在 ASCII 中需要 +55 才能正确表示 32 位格式(A 代表 10等等)。