以特殊的十六进制格式显示整数

时间:2018-09-12 10:50:47

标签: c arrays

我再次面临格式问题。我想将端口号(作为整数)作为参数传递给函数(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

2 个答案:

答案 0 :(得分:1)

在大多数系统上,int的大小为4字节32位。 1234的十六进制表示形式为0x000004d2。在小端系统上(例如x86和x86-64),它以四个字节0xd20x040x000x00 的形式存储在内存中订单

如果我们将其视为字节数组,则看起来像

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

您遇到三个问题:

  1. int的所有四个字节上循环,而只需要有效位
  2. 您不考虑字节序
  3. 您系统上的char已被签名,当升级为int时,它将被符号扩展(根据two's complement规则)

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

要解决第二点,您需要从 end 循环(但仅限于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
}

Proof of concept

答案 1 :(得分:0)

摆脱签名并修改格式。

void foo(int port, int endianess)
{
    unsigned char * _port = (unsigned char*)&port;

    if(endianess)
    {
        for (size_t i = 0; i < 2; i++) 
        {
            printf("\\x%02hhx", _port[i]);
        }
    }
    else
    {
        for (size_t i = sizeof(port) - 1; i >= sizeof(port) - 2; i--) 
        {
            printf("\\x%02hhx", _port[i]);
        }
    }
}