2011-05-04 119 views
4
unsigned char a, b; 
b = something(); 
a = ~b; 

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

我只对提升int的最后一个字节感兴趣 - 如果b是0x55,我需要a为0xAA。我的问题是,C规范是否会说明截断是如何发生的,还是实现定义/未定义?是否保证a将始终得到我预期的价值或在符合的平台上可能出错?

当然,在分配之前转换结果会使静态分析器无声,但是我想知道是否可以安全地忽略此警告。

+1

我会说这是一个虚假的警告。我刚刚通过铛静态分析器运行你的代码,它没有抱怨。什么是'something()'的返回类型 – JeremyP 2011-05-04 10:51:51

+0

@Jeremy这是一个示例代码来说明这种情况。真正的代码就像'mask1 [0] =〜mask2 [0];'两者都是unsigned char类型的数组。显然,我的静态分析器没有叮当声那么聪明:) – Amarghosh 2011-05-04 10:55:44

回答

4

截断发生如6.3.1所述。的C99 Standard

3/2 ...如果新类型是无符号的,则该值是通过重复地加上或减去小于能够在新的类型来表示,直到该值是在最大值多一个转换新型的范围。


示例CHAR_BIT == 8,的sizeof(无符号字符)== 1,的sizeof(int)的== 4

所以,0x55​​的被转换为int,向0x00000055,然后取反到0xFFFFFFAA和

 
     0xFFFFFFAA 
    + 0x00000100 /* UCHAR_MAX + 1 */ 
    ------------ 
     0xFFFFFEAA 

    ... repeat lots and lots of times ... 

     0x000000AA 

或纯0xAA,正如你所期望

+0

Errrr ...这个例子是错误的LOL,但你明白了:) – pmg 2011-05-04 10:56:11

1

它会按照您的意愿行事。投入价值是安全的。

0

让我们以Win32机器为例。
整数是4个字节,并将其转换为字符将导致完全好像剩下的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位计算机)

假设它是小端

+0

-1:是什么让你觉得“整数是4字节”? – 2011-05-04 10:42:03

+0

我试图在这里写出这个概念......假设它是32位机器...... 64位机器或不同的结构体系就概念而言不会有任何区别。0 – Mayank 2011-05-04 10:45:06

+1

@Mayank:为了的其他SO用户可能会在将来阅读您的答案,这很重要,它不包含错误信息 – 2011-05-04 10:46:14

9

C标准指定此为无符号类型:

涉及无符号 操作数可以永远不会溢出,因为 结果是不能被表示的计算生成的无符号整数类型是 减少的模数是一个 的数大于 可由结果 类型表示的最大值。

在这种情况下,如果您的unsigned char是8位,它意味着该结果将模256,这意味着如果b0x55a确实将最终成为0xAA降低。

但是请注意,如果unsigned char更宽比8位(这是完全合法的),您将得到不同的结果。为了确保您将获得可移植作为0xAA的结果,你可以使用:

a = ~b & 0xff; 

(按位,应该从优化平台上,其中unsigned char为8位)。

另请注意,如果您使用签名类型,则结果是实现定义的。

+0

+1。使用'uint8_t'是另一种可能。 – 2011-05-04 10:37:29

+0

它不溢出,我担心(因为这里的操作符是“〜”) - 可以将0xFFFFFFAA截断为char,而不是0xAA(lsb),结果是0xFF(msb)? – Amarghosh 2011-05-04 10:38:06

+0

不,减少总是一个“模2^n”操作,其中n是char中的位数。字节顺序无关 – hirschhornsalz 2011-05-04 10:51:23

0

这个特殊的代码示例是安全的。但是有理由警告不要使用〜操作符。

这背后的原因是,在〜小整数变量是更复杂的表达式存在的潜在问题,因为在C.隐含整数促销试想一下,如果你有一个像

a = ~b >> 4;

它的表达不会像预期的那样转移到零。

如果您的静态分析器设置为包含MISRA-C,那么您会为每个〜运算符得到此警告,因为MISRA强制将小整数类型的任何操作的结果明确地转换为预期类型, char在这种情况下。