我参与了一个项目,我们将 C API 绑定(bind)到 Jython(通过 Java)。我们遇到了无符号值的问题(因为 Java 不支持它们)。我们可以在 Java 和 C 之间使用转换,但从 Jython 迁移到 Java 是一项更困难的任务。
我用 Python 编写了一些“转换”函数。它们将表示有符号或无符号值的位模式转换为表示相反符号的相同位模式。
例如:
>>> u2s(0xFFFFFFFF)
-1L
>>> hex(s2u(-1))
'0xffffffffL'
是否有更优雅的方法来处理 Jython 和 Java 之间的此类符号转换?以前有人尝试过这样做吗?
这是整个模块:
__all__ = ['u2s', 's2u']
def u2s(v,width=32):
"""
Convert a bit pattern representing an unsigned value to the
SAME BIT PATTERN representing a signed value.
>>> u2s(0xFFFFFFFF)
-1L
>>> u2s(0x7FFFFFFF)
2147483647L
"""
msb = int("1" + ((width - 1) * '0'), 2)
msk = int("1" * width, 2)
nv = v & msk
if 0 < (msb & nv):
return -1 * ((nv ^ msk) + 1)
else:
return nv
def s2u(v,width=32):
"""
Convert a bit pattern representing a signed value to the
SAME BIT PATTERN representing an unsinged value.
>>> hex(s2u(-1))
'0xffffffffL'
>>> hex(s2u(1))
'0x1L'
"""
msk = int("1" * width, 2)
if 0 > v:
return msk & (((-1 * v) ^ msk) + 1)
else:
return msk & v
if __name__ == "__main__":
import doctest
doctest.testmod()
我将我的代码与 Jython 中接受的答案进行了基准测试。接受的答案性能提高了约 1/3!我只测试了具有明确定义宽度的版本。
使用以下内容编辑我提供的代码以自行运行基准测试:
def _u2s(v, width=32):
fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width]
return struct.unpack(fmt.lower(), struct.pack(fmt, v))[0]
def _s2u(v, width=32):
fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width]
return struct.unpack(fmt, struct.pack(fmt.lower(), v))[0]
if __name__ == "__main__":
import doctest
doctest.testmod()
import time
x = range(-1000000,1000000)
t1 = time.clock()
y = map(s2u, x)
t2 = time.clock()
print t2 - t1
_t1 = time.clock()
z = map(_s2u, x)
_t2 = time.clock()
print _t2 - _t1
最佳答案
struct模块非常适合这个
import struct
def u2s(v):
return struct.unpack("i", struct.pack("I", v))[0]
def s2u(v):
return struct.unpack("I", struct.pack("i", v))[0]
支持所有常见宽度
import struct
def u2s(v, width=32):
fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width]
return struct.unpack(fmt.lower(), struct.pack(fmt, v))[0]
def s2u(v, width=32):
fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width]
return struct.unpack(fmt, struct.pack(fmt.lower(), v))[0]
支持高达 64 位的任何宽度
import struct
def u2s(v, width=32):
return struct.unpack("q",struct.pack("Q",v<<(64-width)))[0]>>(64-width)
def s2u(v, width=32):
return struct.unpack("Q",struct.pack("q",v<<(64-width)))[0]>>(64-width)
如果需要支持64位以上的宽度
def u2s(v, width=32):
return v if v < (1L<<(width-1)) else v - (1L<<width)
def s2u(v, width=32):
return v if v >= 0 else v + (1L<<width)
关于java - 通过 Java 将无符号值从 Jython 窃取到 C,然后再返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4111595/