负符号 8 位整数的十六进制表示
Hexadecimal representation of a negative signed 8-bit integer
在我的程序的一部分中,我将不得不管理带符号的 8 位整数。我可以使用 printf
和 %d
格式将它们显示为小数。
但是,当涉及到十六进制表示时,负 int8_t
变量的格式不会显示为 8 位十六进制 (0xXX
),而是显示为 32 -bit 十六进制 (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, value);
t = -128;
printf("t = %d = 0x%02X\n", value, value);
return 0;
}
编译执行给出:
t = 0 = 0x00
t = 127 = 0x7F
t = -128 = 0xFFFFFF80
我想要 0x80
而不是 0xFFFFFF80
。我做错了什么?如何将负符号8位整数显示为8位十六进制?
当小于 int
的整数类型被传递给像 printf
这样的可变参数函数时,它们 被提升 为类型 int
。因此,具有值 -1 和表示 0xff 的 int8_t
变成具有值 -1 和表示 0xffffffff 的 int
。
这就是为什么您在使用 %x
时看到的值,它期望并打印 int
。要指示您正在打印 char
值,请使用 %hhx
,这会在打印前将该值转换为 char
。
printf("t = %d = 0x%02hhX\n", value, value);
或者,您可以将值转换为 uint8_t
以更好地匹配 %x
的预期:
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
问题 'sign extension' 的发生是因为,对于您的 %X
格式说明符,预期的参数类型是 int 大小,因此您的 int_8
参数,在被适当提升(和符号扩展)之后,然后被打印为 'full-size' unsigned 整数。
你可以通过在格式中添加 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);
value = -128;
printf("t = %d = 0x%02hhX\n", value, value);
return 0;
}
注意:正如此处评论和其他答案中所指出的,%X
格式说明符(带或不带长度修饰符)用于 signed[ 的参数=45=] 类型在形式上是未定义的行为(尽管它可能适用于绝大多数现代系统)。
为了避免这种潜在的 UB,实现目标的更好方法是 明确地 将你的 int8_t
参数转换为无符号的等价物(相同的位大小——或 uint8_t
,在你的情况下)。然后,当应用“默认参数提升”时,它将执行 没有符号扩展 (因为 [=18= 的所有可能值] 可表示为 int
);因此,不需要将 hh
长度修饰符添加到您的格式中,因为结果 unsigned int
值的高位(添加)位将不会被设置。
此代码以明确定义的方式给出了您想要的结果:
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = 127;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = -128;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
return 0;
}
这是因为整数参数的默认提升。您需要使用正确的格式说明符并强制转换:
int main(void)
{
int8_t value = 0;
printf("t = %d = %02" PRIx8 "\n", value, value);
value = 127;
printf("t = %d = 0x%02" PRIx8 "\n", value,(uint8_t)value);
value = -128;
printf("t = %d = 0x%02" PRIx8 "\n", value, (uint8_t)value);
return 0;
}
此代码有undefined behaviour。 %X
格式说明符的行为仅由语言标准针对 unsigned int
类型参数的情况定义。您改为提供了 int8_t
。
在实践中,您可能(但不能保证)发现 printf
函数试图从存储整数参数的位置读取 unsigned int
,而您所看到的对应于该位置如何被 int8_t
值填充。
I would like to get 0x80 and not 0xFFFFFF80.
0x80
表示值+12810.
要将 -128 打印为 0x80
而没有 未定义的行为 ,请不要尝试使用 "%X"
打印负数。先转换为正数。
t = -128;
// printf("t = %d = 0x%02X\n", value, value);
printf("t = %d = 0x%02X\n", value, (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", value, (unsigned) (uint8_t) value);
在我的程序的一部分中,我将不得不管理带符号的 8 位整数。我可以使用 printf
和 %d
格式将它们显示为小数。
但是,当涉及到十六进制表示时,负 int8_t
变量的格式不会显示为 8 位十六进制 (0xXX
),而是显示为 32 -bit 十六进制 (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, value);
t = -128;
printf("t = %d = 0x%02X\n", value, value);
return 0;
}
编译执行给出:
t = 0 = 0x00
t = 127 = 0x7F
t = -128 = 0xFFFFFF80
我想要 0x80
而不是 0xFFFFFF80
。我做错了什么?如何将负符号8位整数显示为8位十六进制?
当小于 int
的整数类型被传递给像 printf
这样的可变参数函数时,它们 被提升 为类型 int
。因此,具有值 -1 和表示 0xff 的 int8_t
变成具有值 -1 和表示 0xffffffff 的 int
。
这就是为什么您在使用 %x
时看到的值,它期望并打印 int
。要指示您正在打印 char
值,请使用 %hhx
,这会在打印前将该值转换为 char
。
printf("t = %d = 0x%02hhX\n", value, value);
或者,您可以将值转换为 uint8_t
以更好地匹配 %x
的预期:
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
问题 'sign extension' 的发生是因为,对于您的 %X
格式说明符,预期的参数类型是 int 大小,因此您的 int_8
参数,在被适当提升(和符号扩展)之后,然后被打印为 'full-size' unsigned 整数。
你可以通过在格式中添加 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);
value = -128;
printf("t = %d = 0x%02hhX\n", value, value);
return 0;
}
注意:正如此处评论和其他答案中所指出的,%X
格式说明符(带或不带长度修饰符)用于 signed[ 的参数=45=] 类型在形式上是未定义的行为(尽管它可能适用于绝大多数现代系统)。
为了避免这种潜在的 UB,实现目标的更好方法是 明确地 将你的 int8_t
参数转换为无符号的等价物(相同的位大小——或 uint8_t
,在你的情况下)。然后,当应用“默认参数提升”时,它将执行 没有符号扩展 (因为 [=18= 的所有可能值] 可表示为 int
);因此,不需要将 hh
长度修饰符添加到您的格式中,因为结果 unsigned int
值的高位(添加)位将不会被设置。
此代码以明确定义的方式给出了您想要的结果:
int main()
{
int8_t value = 0;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = 127;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
value = -128;
printf("t = %d = 0x%02X\n", value, (uint8_t)value);
return 0;
}
这是因为整数参数的默认提升。您需要使用正确的格式说明符并强制转换:
int main(void)
{
int8_t value = 0;
printf("t = %d = %02" PRIx8 "\n", value, value);
value = 127;
printf("t = %d = 0x%02" PRIx8 "\n", value,(uint8_t)value);
value = -128;
printf("t = %d = 0x%02" PRIx8 "\n", value, (uint8_t)value);
return 0;
}
此代码有undefined behaviour。 %X
格式说明符的行为仅由语言标准针对 unsigned int
类型参数的情况定义。您改为提供了 int8_t
。
在实践中,您可能(但不能保证)发现 printf
函数试图从存储整数参数的位置读取 unsigned int
,而您所看到的对应于该位置如何被 int8_t
值填充。
I would like to get 0x80 and not 0xFFFFFF80.
0x80
表示值+12810.
要将 -128 打印为 0x80
而没有 未定义的行为 ,请不要尝试使用 "%X"
打印负数。先转换为正数。
t = -128;
// printf("t = %d = 0x%02X\n", value, value);
printf("t = %d = 0x%02X\n", value, (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", value, (unsigned) (uint8_t) value);