unsigned char a, b;
b = something();
a = ~b;
静态分析器抱怨最后一行被截断,可能是因为b
在其位被翻转之前被提升为int,结果将是int类型。
我只对提升的int的最后一个字节感兴趣 - 如果b
是0x55,我需要a
为0xAA。我的问题是, C规范是否说明截断发生的方式,还是实现定义/未定义?是否保证a
始终会被赋予我期望的值,或者在符合标准的平台上是否会出错?
当然,在分配之前投射结果会使静态分析器静音,但我想知道首先忽略此警告是否安全。
答案 0 :(得分:9)
C标准为无符号类型指定了这个:
涉及无符号的计算 操作数永远不会溢出,因为a 无法表示的结果 得到的无符号整数类型是 减少模数是一个数 大于最大值 可以用结果来表示 类型。
在这种情况下,如果您的unsigned char
是8位,则意味着结果将以模256减少,这意味着如果b
为0x55
,a
确实会以0xAA
结束。
但请注意,如果unsigned char
更宽而不是8位(这是完全合法的),您将获得不同的结果。为了确保您可以移植0xAA
作为结果,您可以使用:
a = ~b & 0xff;
(按位,应该在unsigned char
为8位的平台上进行优化。)
另请注意,如果使用带符号的类型,则结果是实现定义的。
答案 1 :(得分:5)
截断发生在C99 Standard
的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 ... repeat lots and lots of times ... 0x000000AA
或者像普通0xAA
一样,正如您所期望的那样
答案 2 :(得分:1)
它会按照您的意愿行事。投射价值是安全的。
答案 3 :(得分:0)
让我们来看看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位机器)
假设它是小端
答案 4 :(得分:0)
这个特殊的代码示例是安全的。但有理由警告不要使用〜运算符。
这背后的原因是〜小整数变量是更复杂表达式中的潜在错误,因为C中的隐式整数提升。想象一下,如果你有一个像
这样的表达式 a = ~b >> 4;
它不会像预期的那样以零移动。
如果您的静态分析器设置为包含MISRA-C,您将例如为每个〜运算符获取此警告,因为MISRA强制将对小整数类型的任何操作的结果明确地类型转换为期望类型,unsigned char在这种情况下。