如何将uint32_t转换为无符号字符数组?

3

我正在尝试在Python中复制将uint32_t值转换为unsigned char数组的过程(我已经在C中完成了此操作)。

这是我的现有C函数:

unsigned char *uint32_to_char_array(const uint32_t n)
{
    unsigned char *a;

    a = wrap_calloc(4, sizeof(unsigned char));

    a[0] = (n >> 24) & 0xff;  /* high-order (leftmost) byte: bits 24-31 */
    a[1] = (n >> 16) & 0xff;  /* next byte, counting from left: bits 16-23 */
    a[2] = (n >>  8) & 0xff;  /* next byte, bits 8-15 */
    a[3] = n         & 0xff;  /* low-order byte: bits 0-7 */

    return a;
}

如果我在gdb中执行以下操作:
(gdb) p uint32_to_char_array(0x00240918)[0]@4  = "\000$\t\030"

我正在尝试在Python中生成该字符串。

即,对于输入值为0x240918uint32_t,我希望得到一个输出字符串"\000$\t\030"

我已经搜索了SO,但迄今为止没有结果,特别是这个 -> 如何将整数值转换为Python中的四个字节数组,但没有一个答案似乎能产生上述的输入/输出组合

我正在使用2.7,但如果需要,可以使用> 3.0。

更新:

Python 3.5.2 (default, Nov 12 2018, 13:43:14) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0x240918.to_bytes(4, "big")
b'\x00$\t\x18'

嗯,有些不同——我确定答案就在我的面前,但我看不到它是什么?

那么我能看到:

>>> b"\000$\t\030"
b'\x00$\t\x18'

但是如何实现相反的效果呢?即:
>>> b'\x00$\t\x18'
b"\000$\t\030"

也许问题在于如何以八进制而不是十六进制打印字节文字?

1
似乎to_bytes方法可以回答你提出的问题:在Python 3.7中,0x240918.to_bytes(4, "big") == b"\000$\t\030"返回True。另外,struct.pack('>I', 0x240918)也可以实现相同的功能。 - Mark Dickinson
1
你链接的解决方案是完全相同的代码。(0x00240918 >> i & 0xff) for i in (24,16,8,0)生成的bytes等于b"\000$\t\030",这是正确的。 - Filip Dimitrovski
1
请注意,b'\x00$\t\x18'b"\000$\t\030"是同一字符串的不同表示形式。 - Mark Dickinson
太好了!我怎么才能从一个转换到另一个?也就是说,如何让我的系统打印b"\000$\t\030"而不是b'\x00$\t\x18'? - bph
1个回答

3

嗯,有些不同——我确定答案就在这里,但看不到是什么?

30进制,即"\030"与18进制,即"\x18"相同。它们都代表你的字节序列中一个十进制值为24的单个字节。

您可以在REPL中比较精确值:

bytes((0x00240918 >> i & 0xff) for i in (24,16,8,0)) == b"\000$\t\030"
True

请参考Python官方文档中关于字符串和字节串的语法分析部分:Check the Python documentation on string and byte literals。以下是需要翻译的内容:
  • \ooo: 八进制值为 ooo 的字符
  • \xhh: 十六进制值为 hh 的字符

这些转义字符可以用在字节串和字符串中(请注意,在Python 2 中,字符串是字节序列)。

我认为默认情况下 bytes 不支持八进制表示方法(ASCII编码总是使用十六进制),但你可以自己编写代码实现。

import re
my_b = b'\x00$\t\x18'
print(re.sub(r'\\x([0-9a-f]{2})', lambda a: "\\%03o" % int(a.groups()[0], 16),
  str(my_b)))
# Console result: b'\000$\t\030'

请记住,该字符串包含直接引用和b'前缀,并且可能会接受转义斜杠作为十六进制序列。如果您真的想要一个好的八进制__repr__,最好的方法是创建一个循环并检查非可打印字符,将它们转换为3位八进制,并将所有内容连接成一个字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接