在C中打印十六进制字符

发布于 2024-12-14 15:57:14 字数 423 浏览 2 评论 0原文

我正在尝试读取一行字符,然后打印出该字符的十六进制等效值。

例如,如果我有一个字符串 "0xc0 0xc0 abc123",其中前 2 个字符为十六进制的 c0,其余字符为 abc123 code> 以 ASCII 表示,那么我应该得到

c0 c0 61 62 63 31 32 33

然而,使用 %xprintf 给了我

ffffffc0 ffffffc0 61 62 63 31 32 33

如何在没有“ffffff”?为什么只有 c0(和 80)有 ffffff,而其他字符没有?

I'm trying to read in a line of characters, then print out the hexadecimal equivalent of the characters.

For example, if I have a string that is "0xc0 0xc0 abc123", where the first 2 characters are c0 in hex and the remaining characters are abc123 in ASCII, then I should get

c0 c0 61 62 63 31 32 33

However, printf using %x gives me

ffffffc0 ffffffc0 61 62 63 31 32 33

How do I get the output I want without the "ffffff"? And why is it that only c0 (and 80) has the ffffff, but not the other characters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

壹場煙雨 2024-12-21 15:57:14

您看到 ffffff 是因为 char 在您的系统上已签名。在 C 中,诸如 printf 之类的可变参数函数会将所有小于 int 的整数提升为 int。由于 char 是一个整数(在您的情况下为 8 位有符号整数),因此您的字符将通过符号扩展提升为 int

由于 c080 有一个前导 1 位(并且作为 8 位整数为负),因此它们正在进行符号扩展,而示例中的其他部分则没有t。

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

这是一个解决方案:

char ch = 0xC0;
printf("%x", ch & 0xff);

这将屏蔽掉高位并仅保留您想要的低 8 位。

You are seeing the ffffff because char is signed on your system. In C, vararg functions such as printf will promote all integers smaller than int to int. Since char is an integer (8-bit signed integer in your case), your chars are being promoted to int via sign-extension.

Since c0 and 80 have a leading 1-bit (and are negative as an 8-bit integer), they are being sign-extended while the others in your sample don't.

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

Here's a solution:

char ch = 0xC0;
printf("%x", ch & 0xff);

This will mask out the upper bits and keep only the lower 8 bits that you want.

樱娆 2024-12-21 15:57:14

确实,有类型转换为int。
您还可以使用 %hhx 说明符强制类型为字符。

printf("%hhX", a);

在大多数情况下,您还需要设置最小长度以用零填充第二个字符:

printf("%02hhX", a);

ISO/IEC 9899:201x 说:

7 长度修饰符及其含义是:
hh 指定以下 d、i、o、u、x 或 X 转换说明符适用于
有符号字符或无符号字符参数(该参数将具有
按照整数提升进行提升,但其值应为
在打印之前转换为有符号字符或无符号字符);或者那个
以下

Indeed, there is type conversion to int.
Also you can force type to char by using %hhx specifier.

printf("%hhX", a);

In most cases you will want to set the minimum length as well to fill the second character with zeroes:

printf("%02hhX", a);

ISO/IEC 9899:201x says:

7 The length modifiers and their meanings are:
hh Specifies that a following d, i, o, u, x, or X conversion specifier applies to a
signed char or unsigned char argument (the argument will have
been promoted according to the integer promotions, but its value shall be
converted to signed char or unsigned char before printing); or that
a following

挽心 2024-12-21 15:57:14

您可以创建一个无符号字符:

unsigned char c = 0xc5;

打印它会给出 C5 而不是 ffffffc5

只有大于 127 的字符才会用 ffffff 打印,因为它们是负数(字符有符号)。

或者您可以在打印时强制转换char

char c = 0xc5; 
printf("%x", (unsigned char)c);

You can create an unsigned char:

unsigned char c = 0xc5;

Printing it will give C5 and not ffffffc5.

Only the chars bigger than 127 are printed with the ffffff because they are negative (char is signed).

Or you can cast the char while printing:

char c = 0xc5; 
printf("%x", (unsigned char)c);
千柳 2024-12-21 15:57:14

您可以使用 hh 来告诉 printf表明参数是无符号字符。使用 0 获取零填充,使用 2 将宽度设置为 2。xX 表示小写/大写十六进制字符。

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

编辑:如果读者担心 2501 的断言,即这在某种程度上不是“正确”的格式说明符,我建议他们阅读 printf 链接再次。具体来说:

尽管 %c 需要 int 参数,但传递 char 是安全的,因为调用可变参数函数时会发生整数提升。

固定宽度字符类型(int8_t 等)的正确转换规范在标头 (C++) 或 (C) (尽管 PRIdMAX、PRIuMAX 等与 %jd、%ju 等同义)


至于他关于有符号与无符号的观点,在这种情况下并不重要,因为值必须始终为正数并且很容易适合有符号整数。无论如何,没有带符号的十六进制格式说明符。

编辑2:(“when-to-admit-you're-wrong”版本):

如果您阅读实际的 C11 标准 在第 311 页(PDF 的第 329 页)您会发现:

hh:指定以下 dioux< /code> 或 X 转换说明符适用于 signed charunsigned char 参数(该参数将根据整数提升进行提升) ,但其值应转换为 signed char 或打印前unsigned char);或者以下 n 转换说明符适用于指向 signed char 参数的指针。


You can use hh to tell printf that the argument is an unsigned char. Use 0 to get zero padding and 2 to set the width to 2. x or X for lower/uppercase hex characters.

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

Edit: If readers are concerned about 2501's assertion that this is somehow not the 'correct' format specifiers I suggest they read the printf link again. Specifically:

Even though %c expects int argument, it is safe to pass a char because of the integer promotion that takes place when a variadic function is called.

The correct conversion specifications for the fixed-width character types (int8_t, etc) are defined in the header <cinttypes>(C++) or <inttypes.h> (C) (although PRIdMAX, PRIuMAX, etc is synonymous with %jd, %ju, etc).

As for his point about signed vs unsigned, in this case it does not matter since the values must always be positive and easily fit in a signed int. There is no signed hexideximal format specifier anyway.

Edit 2: ("when-to-admit-you're-wrong" edition):

If you read the actual C11 standard on page 311 (329 of the PDF) you find:

hh: Specifies that a following d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); or that a following n conversion specifier applies to a pointer to a signed char argument.

Smile简单爱 2024-12-21 15:57:14

您可能将值 0xc0 存储在 char 变量中,这可能是有符号类型,并且您的值是负数(最高有效位集)。然后,在打印时,将其转换为 int,并且为了保持语义等价,编译器用 0xff 填充多余的字节,因此负数 int 将具有相同的数值负 char 的值。要解决此问题,只需在打印时转换为 unsigned char 即可:

printf("%x", (unsigned char)variable);

You are probably storing the value 0xc0 in a char variable, what is probably a signed type, and your value is negative (most significant bit set). Then, when printing, it is converted to int, and to keep the semantical equivalence, the compiler pads the extra bytes with 0xff, so the negative int will have the same numerical value of your negative char. To fix this, just cast to unsigned char when printing:

printf("%x", (unsigned char)variable);
回首观望 2024-12-21 15:57:14

您可能正在从带符号的字符数组进行打印。从无符号字符数组打印或用 0xff 屏蔽该值:例如 ar[i] & 0xFF。由于设置了高(符号)位,因此 c0 值正在进行符号扩展。

You are probably printing from a signed char array. Either print from an unsigned char array or mask the value with 0xff: e.g. ar[i] & 0xFF. The c0 values are being sign extended because the high (sign) bit is set.

灯下孤影 2024-12-21 15:57:14

尝试这样的事情:

int main()
{
    printf("%x %x %x %x %x %x %x %x\n",
        0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

产生这样的结果:

$ ./foo 
c0 c0 61 62 63 31 32 33

Try something like this:

int main()
{
    printf("%x %x %x %x %x %x %x %x\n",
        0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

Which produces this:

$ ./foo 
c0 c0 61 62 63 31 32 33
梦屿孤独相伴 2024-12-21 15:57:14

这是一个帮助说明符号扩展的程序。请注意,十六进制中的 0 - 127(0 到 0111 1111)按预期显示,因为符号位为 0,因此当从 8 位到 32 位时,它会用 0 进行扩展(在十六进制中显示为空白)。一旦达到 128 (1000 000) 个有符号字符,它就变成负数 (-128),并且用 1/F 进行符号扩展。

                 unsigned    signed        hex    binary
-----------------------------------------------------------
unsigned char:        127       127         7f    0111 1111
  signed char:        127       127         7f    0111 1111

                 unsigned    signed         hex   binary
---------------------------------------------------------------
unsigned char:        128        128         80   00000000 00000000 00000000 10000000
  signed char:        ...       -128   ffffff80   11111111 11111111 11111111 10000000

程序:

#include <stdio.h>

void print(char c) {
    unsigned char uc = c;
    printf("               %15s %15s %15s\n", "unsigned", "signed", "hex");
    printf("---------------------------------------------------------------\n");
    printf("unsigned char: %15u %15i %15x\n", uc, uc, uc);
    printf("  signed char: %15u %15i %15x\n\n", c, c, c);
}

void main() {
    print(127);
    print(128);
}

即使超过 127,无符号字符也会用 0 扩展,因为您已明确告诉它它是一个正数。

当将有符号字符打印为有符号整数时,您可以看到符号扩展如何保留 -128 的值。

(编辑:将二进制列添加到示例输出中,稍后将其包含在程序代码中)

Here's an program to help illustrate sign extension. Note that 0 - 127 (0 to 0111 1111) in hex shows as expected, because the sign bit is 0, so when going from 8-bit to 32-bit its extended with 0's (which show as blank in the hex). Once you get to 128 (1000 000) signed char, it becomes a negative number (-128), and it is sign-extended with 1's / F's.

                 unsigned    signed        hex    binary
-----------------------------------------------------------
unsigned char:        127       127         7f    0111 1111
  signed char:        127       127         7f    0111 1111

                 unsigned    signed         hex   binary
---------------------------------------------------------------
unsigned char:        128        128         80   00000000 00000000 00000000 10000000
  signed char:        ...       -128   ffffff80   11111111 11111111 11111111 10000000

Program:

#include <stdio.h>

void print(char c) {
    unsigned char uc = c;
    printf("               %15s %15s %15s\n", "unsigned", "signed", "hex");
    printf("---------------------------------------------------------------\n");
    printf("unsigned char: %15u %15i %15x\n", uc, uc, uc);
    printf("  signed char: %15u %15i %15x\n\n", c, c, c);
}

void main() {
    print(127);
    print(128);
}

Unsigned char gets extended with 0's even when going over 127, because you've explicitly told it that its a positive number.

When printing the signed char, as a signed integer, you can see how sign-extending is preserving the value of -128.

(edit: added binary column to the example output, will include this in the program code later)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文