【问题标题】:How to get the signed integer value of a long in python?如何在python中获取long的有符号整数值?
【发布时间】:2010-11-25 10:38:03
【问题描述】:

如果lv存储的是long值,并且机器是32位,如下代码:

iv = int(lv & 0xffffffff)

产生一个 long 类型的 iv,而不是机器的 int。

在这种情况下如何获得(有符号的)int 值?

【问题讨论】:

    标签: python unsigned signed


    【解决方案1】:
    import ctypes
    
    number = lv & 0xFFFFFFFF
    
    signed_number = ctypes.c_long(number).value
    

    【讨论】:

    • ctypes 解决方案根据定义是不好的解决方案。如果你想用 C 编写代码,你应该只使用 C。
    • 我通常不会花时间评论 cmets,但我在这里强烈反对 @Bachsau。我现在正在编写一些(基本上)“丢弃”代码,以从生成 14 位有符号值的设备中采样一堆传感器数据。我只是使用ctypes 将接收到的值签名扩展为ctypes.c_short。我们的产品中已经有 C++ 代码来执行此操作,因此将其“移植”到ctypes 是微不足道的。一旦生命周期测试完成,没有人会再关心这个脚本了。为什么要抨击ctypeshella 对各种系统编程任务都很有用!
    • 如果可行的话,这不是一个糟糕的解决方案。有时,如果您知道自己在做什么,那么能够潜入并调整一些低级的东西会很好。这比其他一些同样需要移位的同样低级的方法要明确得多。
    • 使用ctypes.c_int32 而不是c_long 以确保在所有平台上都是32 位。
    【解决方案2】:

    您正在使用高级脚本语言;从本质上讲,您正在运行的系统的本机数据类型是不可见的。您不能使用这样的代码强制转换为本机签名的 int。

    如果您知道要将值转换为 32 位有符号整数(无论平台如何),您只需使用简单的数学进行转换:

    iv = 0xDEADBEEF
    if(iv & 0x80000000):
        iv = -0x100000000 + iv
    

    【讨论】:

    • 那不准确:所有符合机器词的计算都是在那个级别完成的。例如,~1 == -2。所以我正在寻找一种方法将结果强制转换为 int 类型(这显然不是 int() 所做的)。
    • ~1 == -2 在 all 系统上的 Python 中。如果在本机系统上不是这种情况,那么 Python 实现必须模拟它。 (参见docs.python.org/reference/…)只有当 int 的大小大于 32 位时,本机字大小会泄漏到 Python 中,这意味着您需要稍后从 int 转换为 long。
    • SamB:对于这个问题(正如我所解释的那样——OP 从来没有做出回应的礼貌),就像这种转换得到的一样干净和直接。它比结构更清晰、更明显。当然,它仍然应该隐藏在一个函数中并记录在案。
    • 这个答案可能有点像这样:iv -= (iv & 0x80000000) << 1
    • @Grumdrig:这不可读。 “单行”通常不是一件好事。
    【解决方案3】:

    本质上,问题是将符号从 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
    

    【讨论】:

    • +1 表示不使用条件。它在 Python 中可能没有太大的不同,但确实感觉更令人满意。
    【解决方案4】:

    您可以使用 struct 库来转换这样的值。这很丑陋,但有效:

    from struct import pack, unpack
    signed = unpack('l', pack('L', lv & 0xffffffff))[0]
    

    【讨论】:

    • 如果您使用 order/size/alignment 字符之一,这可以变得可移植。例如,使用'=l''=L' 作为格式字符串。
    【解决方案5】:

    我可以建议一下吗:

    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)
    

    【讨论】:

    • 简洁的解决方案。使用 1
    【解决方案6】:

    一个快速而肮脏的解决方案(在我的例子中,x 永远不会大于 32 位)。

    if x > 0x7fffffff:
        x = x - 4294967296
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-13
      • 1970-01-01
      • 2011-04-12
      • 2012-07-05
      • 2017-04-19
      • 2018-01-15
      相关资源
      最近更新 更多