如何用十六进制表示负char值?

时间:2011-07-11 07:42:38

标签: c char hex signedness

以下代码

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

给编译器警告“由于数据类型的范围有限,比较始终为false”。 当我将支票更改为

时,警告消失了
if(buffer[0]==0xffffffef)

这感觉非常违反直觉。以十六进制检查特定字节值的char的正确方法是什么? (除了使其无符号)

5 个答案:

答案 0 :(得分:6)

错误:

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

答案 1 :(得分:4)

要了解buffer[0] == 0xef触发警告的原因,而buffer[0] == 0xffffffef没有触发警告,您需要准确了解该表达式中发生的事情。

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

C中的常量0xef239之间没有区别:两者都具有类型int和相同的值。如果您的char的范围是-128到127,那么当您评估buffer[0] == 0xef时,buffer[0]会提升为int,从而保持其值不变。因此,它永远不能与0xef相等,因此警告是正确的。

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


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

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

(通过使用unsigned char *类型的单独变量,这显然更方便。

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

答案 2 :(得分:3)

这种情况正在发生,因为buffer内容的类型为char。让它们unsigned char可行:

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

答案 3 :(得分:2)

就像任何其他负数一样:

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

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

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

使用签名字符的原因非常罕见。更罕见的是使用“无符号标识”的原因,可以在不同平台上签名或签名。

答案 4 :(得分:2)

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

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