在C语言中使用小整数与位运算符

10

前一个问题有关,我不理解MISRA C 2004的一些规则。

ISO C99 draft 2007中,6.5节§4:

一些运算符(单目运算符~和二元运算符<<、>>、&、^和|,总称为位运算符)要求其操作数具有整数类型。这些运算符产生的值取决于整数的内部表示,并且对于有符号类型具有实现定义和未定义的方面。

好的,使用带符号整数进行位运算可能会产生未定义的行为(并且没有意义)。

一个好的解决方案是使用显式转换为更宽的无符号整数类型,以绕过整数提升,然后不使用带符号值进行位运算(请参见我之前问题的相关答案)。

但是在MISRA C 2004中,使用小的无符号整数与位运算符是可能的(例如规则10.5)。为什么会这样,如果整数提升导致使用带符号值与位运算符?我认为我还没有理解清楚一些事情。

1
我不确定我理解这个问题,但如果无符号值被提升为更大的类型,这应该没有关系。正数和小于最大有符号值的无符号数看起来是一样的,即符号位为0。 - Caleb
无符号整数类型不会因为整数提升而变成有符号整数类型。例如,无符号短整型始终会变成无符号整型,而不是有符号整型。 - mch
4
在 short 和 int 大小不同的系统上,这并不正确。如果一个无符号短整型可以放入一个 int 中,它将被提升为有符号的 int - Lundin
我在上面的部分中没有看到任何无符号要求。 - phuclv
抱歉,我不理解您的评论。您是什么意思?也许这是一个细节:如果整数提升提供了有符号整数类型,则使用位运算符具有实现定义和未定义的方面。但在这种情况下,整数提升始终提供无符号值(但是带有有符号整数类型),然后使用位运算符就不是问题了。在这种情况下,ISO C99的要求必须是“这些运算符产生依赖于整数的内部表示的值,并且对于有符号值具有实现定义和未定义的方面”,是吗? - no_name
1个回答

1
规则不互相矛盾,您无需扩大类型。您可以立即将小整数二进制操作的结果转换回其类型。
除非第一个操作数是int,否则小整数不会被提升为int以进行移位。
这是他们的示例:
uint8_t port = 0x5aU;
uint8_t result_8;
uint16_t result_16;

result_8 = (~port) >> 4;  /* not compliant */
result_8 = ((uint8_t)(~port)) >> 4; /* compliant */
result_16 = ((uint16_t)(~(uint16_t)port)) >> 4; /* compliant */

4
这个答案不正确。请参考C11 6.5.7节,对每个操作数执行整数提升。结果的类型是左操作数提升后的类型。 - Lundin
我指的是结果,它尊重符号: "E1 >> E2的结果是将E1向右移动E2位。如果E1具有无符号类型或者E1具有带符号类型和非负值,则结果的值是E1 / 2E2商的整数部分" - James
2
E1和E2是指整数提升后的操作数。您引用的文本是指在负数的符号位中移入和移出东西时发生的不良规定行为。 - Lundin
@JamesRoth:我同意:port返回一个带有signed int类型的值,并且对signed int值进行右移可能会产生未定义的行为(这是10.5规则的目标)。但我的问题涉及到位补码操作符(“”)之前的操作数类型。在这种情况下,将uint8_t转换为signed int(整数提升),然后对该类型应用“~”位运算符。在signed int上应用位运算符似乎不是一个好主意,或者我不理解ISO C99。 - no_name
2
@JérômeBurlando 关键是,如果你将 ~ 应用于现在是有符号整数的提升变量,那么您将在最高有效字节中得到垃圾值。然而,如果您立即将变量强制转换回 uint8_t,则会丢弃无用的字节。 - Lundin
显示剩余5条评论

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