如何以十六进制表示负 char 值?
以下代码
char buffer[BSIZE];
...
if(buffer[0]==0xef)
...
向编译器发出警告“由于数据类型范围有限,比较始终为假”。 当我将检查更改为
if(buffer[0]==0xffffffef)
“这感觉非常违反直觉”时,警告就会消失。根据十六进制的特定字节值检查 char
的正确方法是什么? (除了使其未签名之外)
The following code
char buffer[BSIZE];
...
if(buffer[0]==0xef)
...
Gives the compiler warning "comparison is always false due to limited range of data type".
The warning goes away when I change the check to
if(buffer[0]==0xffffffef)
This feels very counterintuitive. What is the correct way to check a char
against a specific byte value in hex? (other than making it unsigned)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有什么问题:
?
What's wrong with:
?
要了解为什么
buffer[0] == 0xef
会触发警告,而buffer[0] == 0xffffffef
不会触发警告,您需要准确了解该表达式中发生的情况。首先,
==
运算符比较两个表达式的值,而不是底层表示 -0xef
是数字 239,并且只会比较相等到那个号码;同样,0xffffffef
是数字 4294967279,并且只会比较等于该数字。C 中的常量
0xef
和239
没有区别:两者都具有int
类型和相同的值。如果您的char
范围为 -128 到 127,那么当您评估buffer[0] == 0xef
时,buffer[0]
会被提升为int
,其值保持不变。因此,它永远不能与0xef
进行比较,因此警告是正确的。但是,常量
0xffffffef
和 4294967279 之间可能存在差异;十进制常量总是有符号的,但十六进制常量可能是无符号的。在您的系统上,它似乎有一个无符号类型 - 可能是unsigned int
(因为该值太大而无法存储在int
中,但又足够小,可以存储在 <代码>无符号整数)。当您计算buffer[0] == 0xffffffef
时,buffer[0]
将提升为unsigned int
。这将保持任何正值不变,但通过向负值添加UINT_MAX + 1
来转换负值;对于范围为 -128 到 127 的char
,提升的值范围为 0 到 127 或 4294967168 到 4294967295。0xffffffef
位于此范围内,因此它比较有可能返回 true。如果您要存储位模式而不是数字,那么您应该首先使用
unsigned char
。或者,您可以通过将指向对象的指针强制转换为unsigned char *
来检查对象的位模式:(这显然通过使用
unsigned char *< 类型的单独变量来更方便地完成/代码>)。
正如 PaulR 所说,您可以还可以使用
buffer[0] == '\xef'
- 这有效,因为'\xef'
被定义为int
常量,其值是位模式为 0xef 的char
对象转换为 int 时所具有的值;例如。在带有符号字符的 2 补码系统上,'\xef'
是值为 -17 的常量。To understand why
buffer[0] == 0xef
triggers a warning, andbuffer[0] == 0xffffffef
does not, you need to understand exactly what's happening in that expression.Firstly, the
==
operator compares the value of two expressions, not the underlying representation -0xef
is the number 239, and will only compare equal to that number; likewise0xffffffef
is the number 4294967279 and will only compare equal to that.There is no difference between the constants
0xef
and239
in C: both have typeint
and the same value. If yourchar
has the range -128 to 127, then when you evaluatebuffer[0] == 0xef
thebuffer[0]
is promoted toint
, which leaves its value unchanged. It can therefore never compare equal to0xef
, so the warning is correct.However, there is potentially a difference between the constants
0xffffffef
and 4294967279; decimal constants are always signed, but hexadecimal constant may be unsigned. On your system, it appears to have an unsigned type - probablyunsigned int
(because the value is too large to store in anint
, but small enough to store in anunsigned int
). When you evaluatebuffer[0] == 0xffffffef
, thebuffer[0]
is promoted tounsigned int
. This leaves any positive value unchanged, but negative values are converted by addingUINT_MAX + 1
to them; with achar
that has range -128 to 127, the promoted values are in either of the ranges 0 to 127 or 4294967168 to 4294967295.0xffffffef
lies within this range, so it is possible for the comparison to return true.If you are storing bit patterns rather than numbers, then you should be using
unsigned char
in the first place. Alternatively, you may inspect the bit pattern of an object by casting a pointer to it tounsigned char *
:(This is obviously more conveniently done by using a separate variable of type
unsigned char *
).As PaulR says, you can also use
buffer[0] == '\xef'
- this works because'\xef'
is defined to be anint
constant with the value that achar
object with the bit pattern 0xef would have when converted to an int; eg. on a 2s complement system with signed chars,'\xef'
is a constant with the value -17.发生这种情况是因为
buffer
内容的类型为char
。让它们成为unsigned char
就可以了:This is happening because
buffer
contents are of typechar
. Making themunsigned char
will work:就像处理任何其他负数一样:
但通常您希望使用 unsigned char 作为数据类型:
使用signed char 的原因非常罕见。更罕见的是使用“无符号规范的字符”的原因,它可以在不同的平台上进行签名或未签名。
Do it just like with any other negative number:
But usually you want to use unsigned char as data type:
Reasons to use signed char are very rare. Even more rare are reasons to use "char without sign specification", which can be signed or unsigned on different platforms.
明确说明原因:
char
是有符号还是无符号是实现定义的。如果您的编译器默认将char
视为有符号,则0xef
将大于可能的最大signed char
(即 127 或0x7f
),因此你的比较将始终是错误的。因此发出警告。其他答案提供了可能的解决方案。
To spell out the reason explicitly: Whether
char
is signed or unsigned is implementation defined. If your compiler treatschar
as signed by default then0xef
will be larger than the largest possibledsigned char
(which is 127 or0x7f
) and therefore your compare will always be false. Hence the warning.Possible solutions are provided by the other answers.