web-dev-qa-db-fra.com

Comment obtenir la valeur entière signée d'un long en python?

Si lv stocke une valeur longue et que la machine est 32 bits, le code suivant:

iv = int(lv & 0xffffffff)

résulte un iv de type long, au lieu de l'int de la machine.

Comment puis-je obtenir la valeur (signée) int dans ce cas?

21
Paul Oyster
import ctypes

number = lv & 0xFFFFFFFF

signed_number = ctypes.c_long(number).value
26
Raony Barrios

Vous travaillez dans un langage de script de haut niveau; par nature, les types de données natifs du système sur lequel vous exécutez ne sont pas visibles. Vous ne pouvez pas transtyper vers un fichier natif signé avec un code comme celui-ci.

Si vous savez que vous souhaitez convertir la valeur en un entier signé 32 bits, quelle que soit la plate-forme, vous pouvez simplement effectuer la conversion avec le calcul simple:

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

Puis-je suggérer ceci:

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

Vous pouvez utiliser struct library pour convertir de telles valeurs. C'est moche, mais ça marche:

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

Le problème est essentiellement de signer une extension de 32 bits à ... un nombre infini de bits, car Python a des entiers arbitrairement grands. Normalement, l’extension de la signature se fait automatiquement par les instructions de la CPU lors de la conversion. Il est donc intéressant de noter que cela est plus difficile en Python qu’en C.

En jouant, j'ai trouvé quelque chose de similaire à la fonction de BreizhGatch, mais cela n'exige pas d'instruction conditionnelle. n & 0x80000000 extrait le bit de signe 32 bits; alors, le - conserve la même représentation 32 bits mais le signe le étend; enfin, les bits de signe étendus sont définis sur n.

def toSigned32(n):
    n = n & 0xffffffff
    return n | (-(n & 0x80000000))

Bit Twiddling Hacks suggère une autre solution qui fonctionne peut-être plus généralement. n ^ 0x80000000 retourne le bit de signe 32 bits; alors - 0x80000000 signera-étendra le bit opposé. Une autre façon de penser est qu’au départ, les nombres négatifs sont supérieurs aux nombres positifs (séparés par 0x80000000); le ^ échange leurs positions; alors le - décale les nombres négatifs en dessous de 0.

def toSigned32(n):
    n = n & 0xffffffff
    return (n ^ 0x80000000) - 0x80000000
6
gengkev

Une solution rapide et sale (x n'est jamais supérieur à 32 bits dans mon cas). 

if x > 0x7fffffff:
    x = x - 4294967296
0
Rob Milne