【问题标题】:Trouble understanding bit shifting as follows无法理解位移如下
【发布时间】:2022-01-05 15:57:47
【问题描述】:

所以我编写了下面的代码,它采用 unsigned int ,将其位向左移动 6 位,然后用另一个 int 值替换空的最后 6 位。但是,当我使用值 15 运行代码时,第一步有效,我得到的值为 960(因此左移 6 有效)。但是 or 步骤似乎不起作用,当我实际需要获取 1111111111111111 或即 65535 时,我得到 -1(注意在这种情况下的操作数值为 -1)?任何帮助将不胜感激。我知道这可能与我的类型有关,但 s->data 被定义为无符号整数,而操作数被定义为 int,所以我不知道为什么 s->data 的输出会给出负值。

typedef struct state { int x, y, tx, ty; unsigned char tool; unsigned int start, data; bool end;} state;

void dataCommand(int operand, state *s) {
    // shifts bits of current data fields six positions to left
    printf("BEFORE SHIFTING %d\n", s->data);
    s->data = s->data << 6;
    printf("AFTER SHIFTING %d\n", s->data);
    printf("OPERAND IS %d\n", operand);
    // last 6 bits replaced with operand bits of the command
    s->data = (s->data | operand);
    printf("AFTER OR %d\n", s->data);

}

【问题讨论】:

  • 如果您的operand-1,这意味着所有位都设置为二进制补码表示。 s-&gt;data 中存储的值无关紧要,因为无论如何都会设置所有位。
  • 你的unsigned int 16 位长吗?然后-165535 在二进制表示方面非常相似。它是 16 位的,全部设置为 1。不同之处只是告诉您的编译器将其视为有符号或无符号值。
  • 请编辑您的问题以包括所有必需的类型定义、调用函数的方式以及打印结果的方式。不要只是描述它,而是显示代码。有关预期的更多详细信息,请参阅MCVE
  • 您正在使用%d 打印unsigned int 值。您应该使用%u,或者更好的可视化位,%x%X
  • 改为以十六进制打印,这样更容易“看到”位模式。或者创建一个函数来打印实际的二进制表示以使其更加清晰。

标签: c bit masking


【解决方案1】:

您必须屏蔽operand 以选择将哪些位组合到结果中。

-1s-&gt;data | operand 表达式中转换为unsigned int,转换为设置了所有位的值UINT_MAX,因此oring operand 设置结果中的所有位,给它一个值@987654327 @,但是由于你使用%d输出值,你得到-1

这样修改代码:

typedef struct state {
    int x, y, tx, ty;
    unsigned char tool;
    unsigned int start, data;
    bool end;
} state;

void dataCommand(int operand, state *s) {
    // shifts bits of current data fields six positions to left
    printf("BEFORE SHIFTING %u\n", s->data);
    s->data = s->data << 6;
    printf("AFTER SHIFTING %u\n", s->data);
    printf("OPERAND IS %d (%#x)\n", operand, operand);
    // last 6 bits replaced with operand bits of the command
    s->data = s->data | (operand & 0x3F);
    printf("AFTER OR %u\n", s->data);
}

【讨论】:

    【解决方案2】:

    operand 为-1 时,它实际上是0xffffffff(二进制中的32 个)。 因此,当您进行 ORing 时,您会返回 32 个仍然是 -1。

    也许您想做的是屏蔽操作数​​的 6 位:

    s->data = (s->data << 6) | (operand & 0b111111);
    

    【讨论】:

    • 感谢这个工作,但我收到以下警告:警告:二进制整数文字是 GNU 扩展 [-Wgnu-binary-literal]。
    • 有没有办法消除这个警告?
    • 您可以用1270x3f 替换0b111111(6 个),但是代码本身并不能说明问题,如果您经常操纵位,我建议禁用警告您的编译器设置,切换标准或忽略它。
    • 非常感谢!
    • @Scouarn.: 0x3F63,而不是 127。更明确的表达式,例如((1U &lt;&lt; 6) - 1) 可能确实更可靠或~(~0U &lt;&lt; 6)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 2014-01-21
    相关资源
    最近更新 更多