按位或运算符在转换为int32之前

3

我在处理数组时注意到了这个问题。例如:

int32_t array[];
int16_t value = -4000;

当我尝试将值写入int32数组值的顶部和底部时,
array[0] = (value << 16) | value;

编译器在进行位移和按位或操作之前会先将值转换为32位的值。因此,如果16位的-4000被写入顶部和底部,顶部的值将是-1,底部的值将是-4000。

有没有办法将16位的-4000 OR进去,使得两个半部分都是-4000?这不是一个很大的问题。我只是好奇是否可以做到。


编译器没有“强制转换”该值;它将其转换了。强制转换是您在源代码中编写的内容,用于告诉编译器进行转换。这被称为显式转换。编译器也可以在不需要强制转换的情况下进行一些转换。这被称为隐式转换 - Pete Becker
5个回答

3

在有些情况下,带符号类型的左移是有定义的。根据标准:

6.5.7/4 [...] 如果 E1 是带符号类型且非负值,并且 E1 × 2E2 在结果类型中是可表示的,则该值为结果;否则,行为未定义。

根据这个定义,看起来你的代码存在未定义的行为。


@harold,我上面引用的话说如果值为负数,则行为是未定义的 - 我有所遗漏吗? - Giorgi Moniava
1
嗯,是的,我想它确实是这么说的。好吧,这又是一篇支持“C语言有害”的文章。 - harold

3
没问题,只需要取消符号扩展即可:

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

不用担心,编译器应该可以合理处理这个

为了避免移动负数:

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

幸运的是,这个额外无用的&(比右侧的更像NOP)不会出现在代码中


你应该避免使用链接缩短器:http://meta.stackoverflow.com/q/313621/1025391 - moooeeeep
@moooeeeep 哇,谢谢Meta..好吧,我会编辑成巨大的链接。 - harold
不要在有符号整数类型上添加更多的位运算,将有符号操作数首先转换为等于或大于unsigned int的无符号整数类型(例如uint32_t)会更有效和更安全,避免整数提升和转换的常见陷阱。 array [0] =(int32_t)(((uint32_t)value <<16)|(uint32_t)value);由于C中不能对小于int的类型执行算术运算,因此始终明确整数转换是一个好习惯。 - sendaran
@sendaran 除了那个不起作用。那么它真的更安全吗?那仍然会进行符号扩展。 - harold
@harold 抱歉,我被其他事情分心了,犯了一个错误。如果有符号类型的秩比 int 低,则需要将中间转换为相同大小的无符号类型以避免符号扩展,因此 array[0] = (int32_t)( ((uint32_t)(uint16_t)value << 16) | (uint32_t)(uint16_t)value );。如果您想要安全和明确,而不是依赖于编译器优化,C 可以在一些看似简单的东西上变得非常冗长。MISRA C 论坛上有一个相关的例子,但我现在找不到它了。 - sendaran

2

使用无符号数值:

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

1
通常在面对这种问题时,我首先将结果值设为零,然后按位赋值。
因此代码应该是:
int32_t array[1];
int16_t value = -4000;
array[0] = 0x0000FFFF;
array[0] &= value;
array[0] |= (value << 16);

你仍然有问题,因为“value”被提升为“int”,并且存在问题的“0xFFFF”。 - Jarod42
@Jarod42 确实,那是一个问题。现在我想一下,对于后面的赋值来说,按位与更合理一些,让我修复代码。 - Vality
@Jarod42 这样做能解决问题吗?我认为可以,但再请一位专业人士帮忙确认一下。 - Vality

0

也要将16进行强制转换。否则int类型会感染。

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

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


父级未平衡,而您仍然存在int提升。 (顺便说一下,有问题的是value - Jarod42
是的,我不测试就评论,活该。 - David Goldfarb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接