如何解决负符号 8 位整数的十六进制表示
在我的程序的一部分中,我必须管理有符号的 8 位整数。我可以使用 printf
和 %d
格式将它们显示为小数。
但是,当涉及到十六进制表示时,负 int8_t
变量的格式不是显示为 8 位十六进制 (0xXX
) 而是显示为 32 位 十六进制 (0xFFFFFFXX
)。
这是描述我的问题的代码片段:
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02X\n",value,value);
t = 127;
printf("t = %d = 0x%02X\n",value);
t = -128;
printf("t = %d = 0x%02X\n",value);
return 0;
}
编译和执行给出:
t = 0 = 0x00
t = 127 = 0x7F
t = -128 = 0xFFFFFF80
我想得到 0x80
而不是 0xFFFFFF80
。我做错了什么?如何将负有符号的 8 位整数显示为 8 位十六进制?
解决方法
有问题的“符号扩展”正在发生,因为对于您的 %X
格式说明符,预期的参数类型是 int 大小,因此您的 int_8
参数,在适当提升(和符号扩展),然后打印为“全尺寸”无符号整数。
可以通过在格式中添加 hh
长度修饰符来防止后面的部分,这表明相应的参数是 char
大小,因此只会打印最低有效字节:
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02hhX\n",value,value);
value = 127;
printf("t = %d = 0x%02hhX\n",value);
value = -128;
printf("t = %d = 0x%02hhX\n",value);
return 0;
}
注意:正如此处的评论和其他答案中所指出的,对 signed 类型的参数使用 %X
格式说明符(带或不带长度修饰符)从形式上讲,是未定义的行为(尽管它可能适用于绝大多数现代系统)。
为了避免这种潜在的 UB,实现目标的更好方法是显式将您的 int8_t
参数强制转换为无符号等效值(具有相同的位大小 – 或 { {1}},就您而言)。然后,当应用“默认参数提升”时,它将不带符号扩展执行(因为 uint8_t
的所有可能值都可以在 { {1}});因此,无需在您的格式中添加 uint8_t
长度修饰符,因为不会设置结果 int
值的高(添加)位。
此代码以明确定义的方式提供您想要的结果:
hh
,
当小于 int
的整数类型被传递给像 printf
这样的可变参数函数时,它们会提升类型为 int
。因此,值为 -1 且表示为 0xff 的 int8_t
变为值为 -1 且表示为 0xffffffff 的 int
。
这就是为什么您在使用 %x
时会看到您的值,它期望并打印一个 int
。要表明您正在打印一个 char
值,请使用 %hhx
,它会在打印前将该值转换为 char
。
printf("t = %d = 0x%02hhX\n",value);
或者,您可以将值强制转换为 uint8_t
以更好地匹配 %x
的预期:
printf("t = %d = 0x%02X\n",(uint8_t)value);
,
此代码有 undefined behaviour。 %X
格式说明符的行为仅由类型为 unsigned int
的参数的情况的语言标准定义。您提供了一个 int8_t
。
在实践中,您可能(但不能保证)发现 printf
函数试图从存储整数参数的位置读取 unsigned int
,您所看到的对应于如何位置被 int8_t
值填充。
这是因为整数参数的默认提升。您需要使用正确的格式说明符和强制转换:
int main(void)
{
int8_t value = 0;
printf("t = %d = %02" PRIx8 "\n",value);
value = 127;
printf("t = %d = 0x%02" PRIx8 "\n",(uint8_t)value);
value = -128;
printf("t = %d = 0x%02" PRIx8 "\n",(uint8_t)value);
return 0;
}
https://godbolt.org/z/jMqhz5156
,我想得到 0x80 而不是 0xFFFFFF80。
0x80
表示值 +12810。
要将 -128 打印为 0x80
而没有未定义的行为,请不要尝试使用 "%X"
打印负数。先转换成正数。
t = -128;
// printf("t = %d = 0x%02X\n",value);
printf("t = %d = 0x%02X\n",(uint8_t) value);
(uint8_t) value
通过添加 256 转换 int8_t
负值。将 uint8_t
传递给 ... 参数将转换为 int
,其值在 [0.. .255]。
"%X"
需要一个 unsigned
。将 int
传递给读取为 ...
的 unsigned
参数是可以的,只要根据 C17dr §6.5.2.2 6 的规定,该值在两者中都可以表示(例如正数)。>
迂腐,不要依赖§6.5.2.2 6:
printf("t = %d = 0x%02X\n",(unsigned) (uint8_t) value);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。