首页 > 解决方案 > 以特殊的十六进制格式显示整数

问题描述

我再次面临格式问题。我想将端口号(作为整数)作为参数传递给函数(argv[]),并希望以特殊格式显示它。在我的实际情况下,我想以十六进制显示端口号 1234。我这样试试

int port = 1234;
char* _port = (char*)&port;
for (int i = 0; i < sizeof(port); i++) {
    printf("\\x%02x", _port[i]);
}

但它显示

\xffffffd2\x04\x00\x00

但我希望它的格式带有前导零和 2 位数字,例如

\x04\xd2

你能帮我吗?

编辑:我把它改成

sizeof(port)-2 

它只显示 2 位数字,但字节序错误:S

标签: carrays

解决方案


在大多数系统上,大小int为 4 个字节,32 位。的十六进制表示12340x000004d2。在 little-endian 系统(如 x86 和 x86-64)上,它像四个字节0xd20x04那样0x00存储在内存中。0x00

如果我们把它看成一个字节数组,它看起来像

+------+------+------+------+
| 0xd2 | 0x04 | 0x00 | 0x00 |
+------+------+------+------+

你有三个问题:

  1. 您循环遍历 的所有四个字节int,而您只需要有效位
  2. 你不考虑字节序
  3. char您系统上的那个是签名的,当提升到int它时将被符号扩展(根据二进制补码规则)

要解决第一点,您需要丢弃“前导”零字节。

要解决第二点,您需要从末尾循环(但仅在 little-endian 系统上)。

要解决第三点,请使用不会进行符号扩展的类型(即uint8_t)。

放在一起你可以做这样的事情:

// The number we want to print
int port = 1234;

// Copy the raw binary data to a buffer
// This buffer is to not break strict aliasing
uint8_t _port[sizeof port];
memcpy(_port, &port, sizeof port);

// Skip leading zeroes in the buffer
// This is done by looping from the end of the buffer to the beginning,
// and loop as long as the current byte is zero
uint8_t *current;
for (current = _port + sizeof _port - 1; current > _port && *current == 0; --current)
{
    // Empty
}

// Print the remaining bytes
for (; current >= _port; --current)
{
    printf("\\x%02x", *current);  // Print with zero-padding, so e.g. \x4 becomes \x04
}

概念证明


推荐阅读