将int截断为char – 是否已定义?
unsigned char a, b; b = something(); a = ~b;
静态分析器抱怨最后一行中的截断,可能是因为b
在其位被翻转之前被提升为int,结果将是int类型。
我只对提升的int的最后一个字节感兴趣 – 如果b
是0x55,我需要a
为0xAA。 我的问题是, C规范是否说明截断发生的方式 ,还是实现定义/未定义? 是否可以保证a
总是被赋予我期望的值或者在符合标准的平台上出错?
当然,在分配之前投射结果会使静态分析器静音,但我想知道首先忽略此警告是否安全。
截断发生在C99标准的 6.3.1.3/2中
…如果新类型是无符号的,则通过重复加或减一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内。
CHAR_BIT == 8,sizeof(unsigned char)== 1,sizeof(int)== 4的示例
因此,0x55转换为int
,转换为0x00000055,然后取反为0xFFFFFFAA,并且
0xFFFFFFAA + 0x00000100 / * UCHAR_MAX + 1 * / ------------ 0xFFFFFEAA ......重复很多次...... 0x000000AA
或者,正如您所期望的那样,简单的0xAA
C标准为无符号类型指定了这个:
涉及无符号操作数的计算永远不会溢出,因为无法通过生成的无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模。
在这种情况下,如果你的unsigned char
是8位,则意味着结果将以模256减少,这意味着如果b
为0x55
,则a
将最终为0xAA
。
但请注意,如果unsigned char
超过8位(这是完全合法的),您将得到不同的结果。 为了确保您可以移植获得0xAA
作为结果,您可以使用:
a = ~b & 0xff;
(按位并应在unsigned char
为8位的平台上进行优化)。
另请注意,如果使用带符号类型,则结果是实现定义的。
它会按照你的意愿行事。 投射价值是安全的。
这个特殊的代码示例是安全的。 但是有理由警告不要使用〜运算符。
这背后的原因是〜小整数变量是更复杂表达式中的潜在错误,因为C中的隐式整数提升。想象一下,如果你有一个像这样的表达式
a = ~b >> 4;
它不会像预期的那样以零的forms移动。
如果您的静态分析器设置为包含MISRA-C,您将例如为每个〜运算符获取此警告,因为MISRA强制将对小整数类型的任何操作的结果明确地类型化为期望类型,在这种情况下为unsigned char 。
让我们来看看Win32机器的情况。
整数是4个字节并将其转换为char将完全像删除了3个字节。
当你将char转换为char时,它被提升到什么并不重要。
~b will add 3 bytes at the left change 0s to 1 and then remove... It does not affect your one right byte.
相同的概念适用于不同的架构(无论是16位还是64位机器)
假设它是小端的