0

以下代码

char buffer[BSIZE];
...
if(buffer[0]==0xef)
...

给编译器警告“由于数据类型的范围有限,比较总是错误的”。当我将检查更改为

if(buffer[0]==0xffffffef)

这感觉非常违反直觉。char根据十六进制的特定字节值检查 a 的正确方法是什么?(除了使其未签名)

4

5 回答 5

6

有什么问题:

if (buffer[0] == '\xef')

?

于 2011-07-11T07:45:07.433 回答
4

要了解为什么buffer[0] == 0xef会触发警告而buffer[0] == 0xffffffef不会触发,您需要准确了解该表达式中发生的情况。

首先,==运算符比较两个表达式的,而不是底层表示 -0xef是数字 239,并且只会比较等于该数字;同样0xffffffef是数字 4294967279 并且只会比较等于。

0xef常量和C中的常量没有区别239:两者都有类型int和相同的值。如果您char的范围为 -128 到 127,那么当您评估 时buffer[0] == 0xefbuffer[0]将提升为int,这使其值保持不变。因此它永远不能比较等于0xef,所以警告是正确的。

但是,常量和 4294967279之间可能存在差异;0xffffffef十进制常量总是有符号的,但十六进制常量可能是无符号的。在您的系统上,它似乎有一个无符号类型 - 可能unsigned int(因为该值太大而无法存储在 中int,但小到足以存储在 中unsigned int)。当您评估buffer[0] == 0xffffffef时,将buffer[0]提升为unsigned int。这使任何正值都保持不变,但是通过将负值相加UINT_MAX + 1来转换它们;对于char范围为 -128 到 127 的 a,提升的值在 0 到 127 或 4294967168 到 4294967295 的任一范围内。 0xffffffef位于此范围内,因此比较可能返回 true。


如果您存储的是位模式而不是数字,那么您应该首先使用unsigned char。或者,您可以通过将指向它的指针转换为来检查对象的位模式unsigned char *

if (((unsigned char *)buffer)[0] == 0xef)

(这显然更方便地通过使用单独的类型变量来完成unsigned char *)。

正如PaulR所说,您也可以使用buffer[0] == '\xef'- 这有效,因为'\xef'它被定义为具有位模式 0xef 的对象在转换为 int 时所int具有的值的常量;char例如。在带有符号字符的 2s 补码系统上,'\xef'是一个值为 -17 的常数。

于 2011-07-11T14:45:24.370 回答
3

发生这种情况是因为buffer内容是 type char。使它们unsigned char起作用:

if ((unsigned char) (buffer[0]) == 0xef)
于 2011-07-11T07:46:10.340 回答
2

就像处理任何其他负数一样:

if (buffer[0]== -0x6f)

但通常你想使用 unsigned char 作为数据类型:

unsigned char buffer[BSIZE];
...
if(buffer[0]==0xef)

使用有符号字符的原因非常少见。更罕见的是使用“char without sign specification”的原因,它可以在不同的平台上签名或未签名。

于 2011-07-11T08:16:01.117 回答
2

明确说明原因:char有符号或无符号是实现定义的。如果您的编译器char默认视为已签名,0xef则将大于最大可能signed char值(即 127 或0x7f),因此您的比较将始终为假。因此发出警告。

其他答案提供了可能的解决方案。

于 2011-07-11T09:18:40.690 回答