【问题标题】:Bitwise or before casting to int32按位或在转换为 int32 之前
【发布时间】:2016-01-04 11:09:37
【问题描述】:

我在搞乱数组并注意到了这一点。例如:

int32_t array[];
int16_t value = -4000;

当我尝试将值写入 int32 数组值的上半部分和下半部分时,

array[0] = (value << 16) | value;

编译器会先将值转换为 32 位值,然后再进行位移和按位 OR。因此,不是将 16 位 -4000 写入上半部和下半部,而是顶部值将是 -1,底部值将是 -4000。

有没有办法在 -4000 的 16 位值中进行或运算,所以两半都是 -4000?这不是一个真正的大问题。我只是想知道它是否可以完成。

【问题讨论】:

  • 编译器没有“转换”值;它转换了它。强制转换是您在源代码中编写的内容,用于告诉编译器进行转换。这称为显式转换。编译器还可以进行一些转换而无需强制转换。这称为隐式转换

标签: c++ c bit-manipulation integer-promotion


【解决方案1】:

当然,只需撤消符号扩展:

array[0] = (value << 16) | (value & 0xFFFF);

别担心,编译器应该handle this reasonably

为避免移动负数:

array[0] = ((value & 0xFFFF) << 16) | (value & 0xFFFF);

幸运的是,额外的无用 &amp;(甚至比右边的那个更像 NOP)doesn't show up in the code

【讨论】:

  • 你应该避免使用链接缩短器:meta.stackoverflow.com/q/313621/1025391
  • @moooeeeep 哇,谢谢 meta.. 很好,我会在巨大的链接中编辑
  • 与其对有符号整数类型添加更多按位运算,不如先将有符号操作数转换为等级等于或大于unsigned int 的无符号整数类型,例如: uint32_t,通过显式避免整数提升和转换的常见陷阱。 array[0] = (int32_t)( ((uint32_t)value &lt;&lt; 16) | (uint32_t)value ); 由于在 C 中不能对小于 int 的类型执行算术运算,因此最好始终明确地使用整数强制转换。
  • @sendaran 除了那不起作用。那么它真的安全多少呢?那仍然会符号扩展。
  • @harold 抱歉,我被其他东西分心了,犯了一个错误。如果有符号类型的等级低于int,则需要中间强制转换为相同大小的无符号类型以避免符号扩展,因此array[0] = (int32_t)( ((uint32_t)(uint16_t)value &lt;&lt; 16) | (uint32_t)(uint16_t)value ); 如果您想要安全和明确,C 可以在一些看似简单的东西上变得非常冗长,而不是依赖编译器优化。 MISRA C 论坛上有一个相关示例,但我现在似乎找不到。
【解决方案2】:

有符号类型的左移仅在某些情况下定义。来自标准

6.5.7/4 [...] 如果 E1 具有有符号类型和非负值,并且 E1 × 2E2 在结果类型中是可表示的,那么这就是结果 价值;否则,行为未定义。

根据这个定义,你所拥有的似乎是未定义的行为。

【讨论】:

  • @harold 我上面的引述说,如果价值是消极的行为是 UB - 我错过了什么吗?
  • 嗯,是的,我想它确实这么说。好吧,“C 被认为有害”还有一个
【解决方案3】:

使用无符号值:

const uint16_t uvalue = value
array[0] = (uvalue << 16) | uvalue;

【讨论】:

    【解决方案4】:

    通常在遇到此类问题时,我首先将结果值设置为零,然后按位分配值。

    所以代码是:

    int32_t array[1];
    int16_t value = -4000;
    array[0] = 0x0000FFFF;
    array[0] &= value;
    array[0] |= (value << 16);
    

    【讨论】:

    • 你还是有问题,因为value 升级为int 有问题0xFFFF
    • @Jarod42 没错,这实际上是一个问题。现在我稍微考虑一下,对于后面的分配会更理智,让我修复代码
    • @Jarod42 可以解决这个问题吗,我想可以,但是第二双眼睛会有所帮助
    【解决方案5】:

    也投 16 个。否则 int 类型具有传染性。

    array[0] = (value &lt;&lt; (int16_t 16)) | value;

    编辑:我没有方便测试的编译器。根据下面的评论,这可能不正确,但会让您朝着正确的方向前进。

    【讨论】:

    • 父母不平衡,您仍有int 促销。 (有问题的是value btw)
    • 是的,我可以在没有测试的情况下发表评论。
    猜你喜欢
    • 2015-03-14
    • 2019-04-28
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多