繁体   English   中英

将实现特定的C ++字符与Python中的uint32_t匹配

[英]Match implementation specific C++ char to uint32_t cast in Python

请考虑以下C ++程序:

#include <cstdint>
#include <iostream>

int main() {
  std::string s = "αa";
  std::cout << std::hex << uint32_t(s[0]) << std::endl;
  std::cout << std::hex << uint32_t(s[1]) << std::endl;
  std::cout << std::hex << uint32_t(s[2]) << std::endl;
}

哪个打印

ffffffce
ffffffb1
61

如何在Python中复制转换行为? IE浏览器。 如何获取包含3个数字的uint32_t类型的numpy数组? 1

例如

import numpy as np

s = "αa"
s = s.encode('utf-8')
for c in bytearray(s):
    h = print(hex(np.uint32(c)))

将导致

0xce
0xb1
0x61

这还不够。 我也研究了ctypes模块提供的功能,但找不到可行的解决方案。

动机:我想应用一个Fowler-Noll-Vo哈希函数 ,该函数依赖于按位运算,并与通过将std::string的元素转换为uint32_t操作的现有C ++实现相匹配。

1虽然C ++版本的输出取决于体系结构/编译器,但我正在寻找一种实现方案,该实现方案与该问题中描述的行为匹配,或者与使用python解释器的编译器相同的编译器进行编译时,C ++程序的行为匹配继续。

根据Python文档。

字节数组类型是一个可变的整数序列,范围为0 <= x <256。

恕我直言,因此C ++中的转换应将字符处理为unsigned char 这可以通过“两步”强制转换来实现:

#include <cstdint>
#include <iostream>

typedef unsigned char uchar;

int main() {
  std::string s = "αa";
  std::cout << std::hex << uint32_t((uchar)s[0]) << std::endl;
  std::cout << std::hex << uint32_t((uchar)s[1]) << std::endl;
  std::cout << std::hex << uint32_t((uchar)s[2]) << std::endl;
}

输出:

ce
b1
61

在coliru上进行现场演示

笔记:

  1. 我认为初始化std::string s = "αa"; 有点关键。 因此,这取决于源代码编码。 (我在Windows上。许多Windows应用程序通常都使用Windows-1252编码会破坏该程序, 因为字符串仅包含两个元素 。我只是意识到Window-1252甚至不编码α但是并没有使它变得更好。)

  2. 强制将字符设置为unsigned char ,应使应用程序独立于C ++编译器的特定char类型的签名。

这里的问题是,您的C ++实现(标准所做的很多事情,不幸的是允许但没有强制执行 )将char作为有符号类型,而Python正确地将bytearray元素视为非负值。

IMO的正确解决方案将如@Scheff在他的答案中所示-修复C ++程序,该程序依赖于实现定义的行为,该行为会产生有争议的输出。 OTOH,如果您不得不匹配无法更改的现有C ++程序,则可以轻松地在Python中重现此行为。

在您的C ++程序中,当超出127的字节值(因此为负)转换为uint32_t ,它将被包裹在ffffffxx左右,因此所有ffffffxx值都将被包装。

为了在Python中获得相同的结果,您可以先手动将其转换为int8 (即C ++实现中的char ):

import numpy as np

s = "αa"
s = s.encode('utf-8')
for c in bytearray(s):
    h = print(hex(np.uint32(np.int8(c))))

输出:

0xffffffce
0xffffffb1
0x61

第一个字符为0xffffffce的事实取决于实现,并且有效的C ++实现也可能返回0xce因为差异取决于默认的char类型是带符号的还是无符号的(某些编译器提供了命令行开关来更改行为,因此不是甚至仅依赖于平台,但依赖于编译选项)。

也就是说,您可以通过简单地扩展第8位或在转换之前将其转换为相应的带符号的值,将转换为uint32的无符号字符固定为与带符号的字符转换相同的结果。例如

print(hex(np.uint32(c if c < 128 else c-256)))

获取uint32的numpy数组的一种方法是首先将其传递给int8数组:

>>> s = 'αa'
>>> a = np.array(list(s.encode('utf8')),dtype=np.int8)
>>> b = np.array(a,dtype=np.uint32)
>>> b
array([4294967246, 4294967217,         97], dtype=uint32)
>>> for c in b: print(hex(c))
...
0xffffffce
0xffffffb1
0x61

暂无
暂无

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

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