将实现特定的C ++ char匹配到Python中的uint32_t

时间:2018-06-19 02:00:26

标签: python c++ numpy casting ctypes

考虑以下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 hash function,它依赖于逐位操作,匹配现有的C ++实现,该实现通过将std::string的元素转换为uint32_t来运行。

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

编译的

4 个答案:

答案 0 :(得分:2)

根据Python doc.

  

bytearray类型是0 <= x <0的范围内的可变整数序列。 256。

恕我直言,因此C ++中的转换应该将字符处理为unsigned char。这可以通过&#34;两步&#34;投:

#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

Live Demo on coliru

注意:

  1. 我认为初始化std::string s = "αa";有点关键。所以,这取决于源代码编码。 (我在Windows上。使用Windows-1252编码,因为它通常用于很多Windows应用程序会破坏这个程序,因为字符串只有两个元素。我刚才意识到{{ 3}}甚至不编码α,但这并不能使它更好。)

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

答案 1 :(得分:2)

这里的问题是你的C ++实现(不可避免地允许 - 但不是强制的 - 标准)将For example , if arr={6,3,1,3,4,3,6,5}; after sort arr={1,3,3,3,4,5,6,6}; And number of similar elements from end is 2. 作为签名类型,而Python正确地考虑char个元素为非负值。

正确的解决方案IMO将像@Scheff在其答案中所示 - 修复C ++程序,该程序依赖于生成有争议输出的实现定义行为。 OTOH,如果你被迫匹配一个无法改变的现有C ++程序,你可以很容易地在Python中重现这种行为。

在C ++程序中,当字节值超过127(因而为负数)转换为bytearray时,它会被包裹在2³²左右,因此所有uint32_t值都会被包含。

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

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))))

答案 2 :(得分:1)

第一个字符获得0xffffffce的事实依赖于实现,有效的C ++实现也可以返回0xce,因为差异取决于签名或未签名的默认char类型(有些编译器提供了一个命令行开关来改变行为,所以它甚至不仅仅依赖于平台,而是依赖于编译选项。)

那就是说你可以通过简单地扩展第8位或者在进行转换之前转换为相应的有符号值来将转换为uint32的无符号字符修改为转换有符号字符的相同结果...例如

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

答案 3 :(得分:0)

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

 con_id         date_updated         type     
--------------------------------------------
123              19/06/2018          2
101              07/06/2018          1