逐位或在转换为int32之前



我在摆弄数组时注意到了这一点。例如:

int32_t array[];
int16_t value = -4000;

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

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

编译器将在进行位移位和逐位OR之前首先将该值强制转换为32位值。因此,不是在上半部分和下半部分写入16位-4000,而是顶部值为-1,底部值为-4000。

有没有办法对-4000的16位值进行OR运算,这样两半都是-4000?这并不是一个大问题。我只是想知道它是否能做到。

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

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

别担心,编译器应该合理地处理这个问题。

为了避免移动负数:

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

幸运的是,额外无用的&(甚至比右边的更像NOP)没有出现在代码中。

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

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

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

使用无符号值:

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

通常,当遇到这种问题时,我首先将结果值设置为零,然后按位分配.中的值

所以代码是:

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

也铸造16。否则,int类型具有传染性。

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

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

最新更新