【发布时间】:2010-11-25 10:38:03
【问题描述】:
如果lv存储的是long值,并且机器是32位,如下代码:
iv = int(lv & 0xffffffff)
产生一个 long 类型的 iv,而不是机器的 int。
在这种情况下如何获得(有符号的)int 值?
【问题讨论】:
如果lv存储的是long值,并且机器是32位,如下代码:
iv = int(lv & 0xffffffff)
产生一个 long 类型的 iv,而不是机器的 int。
在这种情况下如何获得(有符号的)int 值?
【问题讨论】:
import ctypes
number = lv & 0xFFFFFFFF
signed_number = ctypes.c_long(number).value
【讨论】:
ctypes 将接收到的值签名扩展为ctypes.c_short。我们的产品中已经有 C++ 代码来执行此操作,因此将其“移植”到ctypes 是微不足道的。一旦生命周期测试完成,没有人会再关心这个脚本了。为什么要抨击ctypes? hella 对各种系统编程任务都很有用!
ctypes.c_int32 而不是c_long 以确保在所有平台上都是32 位。
您正在使用高级脚本语言;从本质上讲,您正在运行的系统的本机数据类型是不可见的。您不能使用这样的代码强制转换为本机签名的 int。
如果您知道要将值转换为 32 位有符号整数(无论平台如何),您只需使用简单的数学进行转换:
iv = 0xDEADBEEF
if(iv & 0x80000000):
iv = -0x100000000 + iv
【讨论】:
iv -= (iv & 0x80000000) << 1
本质上,问题是将符号从 32 位扩展到...无限位,因为 Python 具有任意大的整数。通常,符号扩展是由 CPU 指令在强制转换时自动完成的,因此有趣的是,在 Python 中这比在 C 中更难。
通过玩弄,我发现了一些类似于 BreizhGatch 的函数,但它不需要条件语句。 n & 0x80000000 提取 32 位符号位;然后,- 保持相同的 32 位表示,但对其进行符号扩展;最后,在n 上设置扩展符号位。
def toSigned32(n):
n = n & 0xffffffff
return n | (-(n & 0x80000000))
Bit Twiddling Hacks 提出了另一种可能更普遍的解决方案。 n ^ 0x80000000 翻转 32 位符号位;然后- 0x80000000 将对相反位进行符号扩展。另一种思考方式是,最初,负数高于正数(以0x80000000 分隔); ^ 交换他们的位置;然后- 将负数移到 0 以下。
def toSigned32(n):
n = n & 0xffffffff
return (n ^ 0x80000000) - 0x80000000
【讨论】:
您可以使用 struct 库来转换这样的值。这很丑陋,但有效:
from struct import pack, unpack
signed = unpack('l', pack('L', lv & 0xffffffff))[0]
【讨论】:
'=l' 和'=L' 作为格式字符串。
我可以建议一下吗:
def getSignedNumber(number, bitLength):
mask = (2 ** bitLength) - 1
if number & (1 << (bitLength - 1)):
return number | ~mask
else:
return number & mask
print iv, '->', getSignedNumber(iv, 32)
【讨论】:
一个快速而肮脏的解决方案(在我的例子中,x 永远不会大于 32 位)。
if x > 0x7fffffff:
x = x - 4294967296
【讨论】: