将int截断为char - 是否已定义?

时间:2011-05-04 10:21:44

标签: c bitwise-operators integer-promotion

unsigned char a, b;
b = something();
a = ~b;

静态分析器抱怨最后一行被截断,可能是因为b在其位被翻转之前被提升为int,结果将是int类型。

我只对提升的int的最后一个字节感兴趣 - 如果b是0x55,我需要a为0xAA。我的问题是, C规范是否说明截断发生的方式,还是实现定义/未定义?是否保证a始终会被赋予我期望的值,或者在符合标准的平台上是否会出错?

当然,在分配之前投射结果会使静态分析器静音,但我想知道首先忽略此警告是否安全。

5 个答案:

答案 0 :(得分:9)

C标准为无符号类型指定了这个:

  

涉及无符号的计算   操作数永远不会溢出,因为a   无法表示的结果   得到的无符号整数类型是   减少模数是一个数   大于最大值   可以用结果来表示   类型。

在这种情况下,如果您的unsigned char是8位,则意味着结果将以模256减少,这意味着如果b0x55a确实会以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在这种情况下。