简体   繁体   English

负符号 8 位 integer 的十六进制表示

[英]Hexadecimal representation of a negative signed 8-bit integer

In a portion of my program, I'll have to manage signed 8-bit integers.在我的程序的一部分中,我必须管理有符号的 8 位整数。 I have no problem to display them as decimals using printf and %d formatting.使用printf%d格式将它们显示为小数没有问题。

However, when it comes to hexadecimal representation, the formatting of a negative int8_t variable is not shown as a 8-bit hexadecimal ( 0xXX ) but as a 32-bit hexadecimal ( 0xFFFFFFXX ).但是,当涉及到十六进制表示时,负int8_t变量的格式不显示为 8 位十六进制 ( 0xXX ),而是显示为32 位十六进制 ( 0xFFFFFFXX )。

Here is the snippet of code, describing my problem:这是描述我的问题的代码片段:

#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;
}

Compilation and execution give:编译和执行给出:

t = 0 = 0x00
t = 127 = 0x7F
t = -128 = 0xFFFFFF80

I would like to get 0x80 and not 0xFFFFFF80 .我想得到0x80而不是0xFFFFFF80 What did I do wrong?我做错了什么? How to display the negative signed 8-bit integer as a 8-bit hexadecimal?如何将负符号 8 位 integer 显示为 8 位十六进制?

The problematic 'sign extension' is happening because, for your %X format specifier, the expected argument type is of int size, so your int_8 argument, after being suitably promoted (and sign-extended), is then printed as a 'full-size' unsigned integer.有问题的“符号扩展”正在发生,因为对于您的%X格式说明符,预期的参数类型是int大小,因此您的int_8参数在被适当提升(和符号扩展)后,然后打印为“完整-大小'无符号integer。

You can prevent the latter part by adding the hh length modifier to the format, which indicates that the corresponding argument is of char size, so only the least-significant byte will be printed:您可以通过在格式中添加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;
}

Further Reference进一步参考


Note: As pointed out in the comments here, and in other answers, the use of the %X format specifier (with or without a length modifier) for an argument of signed type is, formally, undefined behaviour (though it will likely work on the vast majority of modern systems).注意:正如这里的评论和其他答案中所指出的,对有符号类型的参数使用%X格式说明符(带或不带长度修饰符)在形式上是未定义的行为(尽管它可能适用于绝大多数现代系统)。

To avoid such potential UB, a better way to achieve your goal is to explicitly cast your int8_t argument(s) to the unsigned equivalent (of the same bit size – or uint8_t , in your case).为了避免这种潜在的 UB,实现目标的更好方法是将int8_t参数显式转换为无符号等效项(在您的情况下具有相同的位大小 - 或uint8_t )。 Then, when the "default argument promotion" is applied, it will be performed without sign extension (as all possible values of a uint8_t are representable in an int );然后,当应用“默认参数提升”时,它将在没有符号扩展的情况下执行(因为uint8_t的所有可能值都可以在int中表示); thus, there will then be no need to add the hh length modifier to your format, as the upper (added) bits of the resultant unsigned int values will not be set.因此,无需将hh长度修饰符添加到您的格式中,因为不会设置结果unsigned int值的高位(添加)。

This code gives your desired result in a well-defined way:此代码以明确定义的方式给出您想要的结果:

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;
}

When integer types smaller than int are passed to a variadic function like printf they are promoted to type int .当小于int的 integer 类型传递给可变参数 function (如printf时,它们被提升为int类型。 So a int8_t with value -1 and representation 0xff becomes an int with value -1 and representation 0xffffffff.因此,值为 -1 且表示为 0xff 的int8_t变为值为 -1 且表示为 0xffffffff 的int

That's why you're seeing the values you are while using %x which expects and prints an int .这就是为什么您在使用%x时看到的值,它期望并打印一个int To indicate that you're printing a char value, use %hhx which will convert the value to char before printing.要表明您正在打印一个char值,请使用%hhx它将在打印之前将该值转换为char

printf("t = %d = 0x%02hhX\n", value, value);

Alternately, you can cast the value to uint8_t to better match what %x expects:或者,您可以将该值强制转换为uint8_t以更好地匹配%x的预期:

printf("t = %d = 0x%02X\n", value, (uint8_t)value);

This code has undefined behaviour .此代码具有未定义的行为 The behaviour of the %X format specifier is only defined by the language standard for the case of an argument of type unsigned int . %X格式说明符的行为仅由语言标准针对unsigned int类型的参数的情况定义。 You provided an int8_t instead.您提供了一个int8_t

In practice you may (but this is not guaranteed) find that the printf function tries to read an unsigned int from the location where integer arguments are stored, and what you are seeing corresponds to how that location gets filled up by an int8_t value. In practice you may (but this is not guaranteed) find that the printf function tries to read an unsigned int from the location where integer arguments are stored, and what you are seeing corresponds to how that location gets filled up by an int8_t value.

This is because of default promotion of integer arguments.这是因为默认提升 integer arguments。 You need to use correct format specifiers and cast:您需要使用正确的格式说明符并强制转换:

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;
}

https://godbolt.org/z/jMqhz5156 https://godbolt.org/z/jMqhz5156

I would like to get 0x80 and not 0xFFFFFF80.我想得到 0x80 而不是 0xFFFFFF80。

0x80 represents the value +128 10 . 0x80表示值 +128 10

To print -128 as 0x80 without undefined behavior , do not attempt to print negative numbers with "%X" .要将 -128 打印为0x80而没有未定义的行为,请不要尝试使用"%X"打印负数。 Convert to a positive number first.先转换成正数。

t = -128;
// printf("t = %d = 0x%02X\n", value, value); 
printf("t = %d = 0x%02X\n", value, (uint8_t) value); 

(uint8_t) value converts int8_t negative values by adding 256. Passing the uint8_t to a... argument converts to an int with values in the range [0...255]. (uint8_t) value通过添加 256 来转换int8_t负值。将uint8_t传递给 ... 参数将转换为值在 [0...255] 范围内的int

"%X" expects an unsigned . "%X"需要一个unsigned Passing an int to a ... argument that is read as an unsigned is OK as long as the value is representable in both (eg positive) per C17dr §6.5.2.2 6.int传递给读取为unsigned...参数是可以的,只要该值在 C17dr §6.5.2.2 6 中都可以表示(例如正数)。

Pedantically, to not rely on §6.5.2.2 6:迂腐地,不依赖 §6.5.2.2 6:

printf("t = %d = 0x%02X\n", value, (unsigned) (uint8_t) value); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM