【问题标题】:Extracting two signed integers from one given integer?从一个给定整数中提取两个有符号整数?
【发布时间】:2012-11-21 01:59:29
【问题描述】:

我有以下结构:

struct
{
   int a:4;
   int b:7;
   int c:21;
} example;

我想在 C++ 中将 a 和 b 组合成一个整数 d。例如,我希望 a 的位值位于 b 的位值的左侧,以便形成整数 d。这是如何在 C++ 中实现的?

例子:

a= 1001

b = 1010101

我想要 int d = 10011010101 xxxxxxxxxxxxxxxxxxxxx

其中 x 可以是以前属于 d 的 21 位。我希望将 a 和 b 的值分别放在位位置 0-3 和 4-10 中,因为 a 占据结构“示例”中的前 4 位,b 占据接下来的 7 位。

我感到困惑的部分是变量 a 和变量 b 在最高有效位都有一个“符号”位。这会影响结果吗?变量 a 和变量 b 中的所有位是否都用于整数 d 的最终结果?整数 d 是否看起来像变量 a 的位和变量 b 的位的串联?

谢谢

【问题讨论】:

  • 您如何计算位位置?通常,位 0 是最低有效位 (LSB),位 31 是 32 位整数的最高有效位 (MSB)。您的图表表明您希望位 0-10 比位 11-31 更重要。

标签: c++ bit-manipulation


【解决方案1】:

请注意,int 位域是有符号还是无符号是实现定义的。 C++ 标准是这么说的,而 C 标准用不同的措辞实现了相同的最终结果:

ISO/IEC 14882:2011 — C++

§7.1.6.2 简单类型说明符

¶3 ... [注意:char 类型的对象和某些位域(9.6)是否是实现定义的 表示为有符号或无符号数量。 signed 说明符强制 char 对象和位域为 签;它在其他情况下是多余的。 ——尾注]

§9.6 位域

¶3 ... 位域应具有整数或枚举类型 (3.9.1)。这是 实现定义是否是一个普通的(既没有显式签名也没有无符号)charshortintlong, 或long long 位域有符号或无符号。

ISO/IEC 9899:2011 — C

§6.7.2.1 结构和联合说明符

¶10 位域被解释为具有由指定位数组成的有符号或无符号整数类型。125)

125) 如上面 6.7.2 所述,如果实际使用的类型说明符是 int 或定义为 int 的 typedef-name,则位域是否带符号由实现定义或未签名。

§6.7.2 类型说明符

¶5 ... 对于位域,说明符 int 是否指定与 signed int 相同的类型或与 unsigned int 相同的类型是实现定义的。

第 6.7.2 节的上下文表明 int 可以与 shortlong 等组合,并且适用该规则; C++ 更清楚地说明了这一点。当然,普通char 的签名已经由实现定义了。


无符号位域

如果位域的类型是无符号的,那么表达式相当简单:

int d = (example.a << 7) | example.b;

有符号位域

如果这些值是有符号的,那么您需要进行主要的解释练习,确定如果example.a 为负数而example.b 为正数,则该值应为多少,反之亦然。在某种程度上,即使值都为负或均为正,也会出现问题。

假设example.a = 7;example.b = 12;d 的值应该是多少?可能同样的表达式适用,但您可能会争辩说最好少移动 1 个位置:

assert(example.a >= 0 && example.b >= 0);
int d = (example.a << 6) | example.b;      // Alternative interpretation

其他情况由您决定;这取决于您要对这些值进行的解释。例如:

int d = ((example.a & 0x0F) << 7) | (example.b & 0x7F);

这会强制将有符号值视为无符号值。这可能不是你想要的。


修改后的问题

example.a = 1001     // binary

example.b = 1010101  // binary

d = 10011010101 xxxxxxxxxxxxxxxxxxxxx

其中 x 可以是之前属于 d 的 21 位。

为此,您需要:

  d = (d & 0x001FFFFF) | ((((example.a & 0x0F) << 7) | (example.b & 0x7F)) << 21);

您可能可以使用更少的括号;我不确定我是否会冒险这样做。

联合

但是,使用此修订后的规范,您可能很想查看union,例如:

union u
{
    struct
    {
       int a:4;
       int b:7;
       int c:21;
    } y;
    int x;
} example;

但是,未指定位域中的位布局 w.r.t int x; 中的位(它们可能是最高有效位在前或最低有效位在前),并且总是有关于“如果你访问联合中的一个值,该值不是分配给您的最后一个值调用未定义的行为。因此,您需要处理位字段的多个平台定义方面。事实上,这种难题通常意味着位域与一种特定类型的机器 (CPU) 以及编译器和操作系统密切相关。就您所追求的细节而言,它们非常非常不便携。

【讨论】:

  • +1:我仍然想知道为什么这是为int 而不是其他整数类型指定的(或者它们是我读错了规范?)。直到今天,当我看到int x:1 时,我偶尔会笑。具有位宽的有符号值的想法仍然让我感到震惊。
  • @WhozCraig:请参阅我关于“§6.7.2 的上下文”的注释。在描述short intlong long int 等的行中提到了int,我相信这一点已经涵盖。可以说,C++ 标准使其更加清晰。
猜你喜欢
  • 2011-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-22
  • 1970-01-01
  • 2013-02-04
  • 2012-02-11
相关资源
最近更新 更多