2009-09-03 28 views

Trả lời

13

Bạn đang làm việc bằng ngôn ngữ kịch bản cấp cao; về bản chất, các kiểu dữ liệu gốc của hệ thống bạn đang chạy không hiển thị. Bạn không thể truyền tới một int có chữ ký gốc với mã như thế này.

Nếu bạn biết rằng bạn muốn giá trị chuyển đổi sang một số nguyên ký 32-bit - bất kể nền tảng này - bạn chỉ có thể thực hiện chuyển đổi với toán học đơn giản:

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

Điều đó không chính xác: tất cả các tính toán phù hợp với từ của máy được thực hiện ở cấp đó. Ví dụ: ~ 1 == -2. Vì vậy, tôi đang tìm một cách để buộc kết quả vào loại int (mà không phải là những gì int() hiện, rõ ràng). –

+0

~ 1 == -2 bằng Python trên * tất cả * hệ thống. Nếu đó không phải là trường hợp trên hệ thống bản địa, thì việc triển khai Python phải mô phỏng nó. (Xem http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy.) Lần duy nhất kích thước từ gốc có thể bị rò rỉ vào Python là khi kích thước của int lớn hơn 32 bit , có nghĩa là bạn làm cho transtion từ int đến lâu sau đó. –

+0

Bạn không thể buộc Python chuyển đổi một giá trị dài thành int khi giá trị không khớp với một int; bạn không thể viết mã Python như thể bạn đang ở trong C.Nếu bạn muốn chuyển đổi giá trị int 32 bit không được gán 0xFFFFFFFF thành số nguyên 32 bit được bổ sung của hai ký tự đại diện bởi cùng một chuỗi bit, thì tôi đã cho bạn mã. Nếu không, tôi không chắc bạn đang cố gắng làm gì. –

5

Bạn có thể sử dụng struct thư viện để chuyển đổi các giá trị như vậy. Nó xấu xí, nhưng hoạt động:

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

Tính năng này hoạt động trên các máy 32 bit và không hoạt động trên 64 bit – nkrkv

+3

Điều này có thể được thực hiện di động nếu bạn sử dụng một trong các ký tự thứ tự/kích thước/căn chỉnh. Ví dụ, sử dụng ''= l'' và'' = L'' làm các chuỗi định dạng. – SamB

19
import ctypes 

number = lv & 0xFFFFFFFF 

signed_number = ctypes.c_long(number).value 
6

Tôi có thể đề nghị này:

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

Về cơ bản, vấn đề là phải ký kéo dài từ 32 bit để ... vô số bit, vì Python có số nguyên lớn tùy ý. Thông thường, phần mở rộng ký tự được thực hiện tự động theo hướng dẫn của CPU khi truyền, vì vậy điều thú vị là điều này khó hơn trong Python, ví dụ: C.

Bằng cách chơi xung quanh, tôi đã tìm thấy một cái gì đó tương tự như chức năng của BreizhGatch, nhưng không yêu cầu một tuyên bố có điều kiện. n & 0x80000000 trích xuất bit dấu 32 bit; sau đó, - giữ nguyên biểu diễn 32 bit nhưng ký mở rộng nó; cuối cùng, các bit dấu mở rộng được đặt trên n.

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

Bit Twiddling Hacks đề xuất một giải pháp khác có thể hoạt động chung hơn. n^0x80000000 lật bit bit 32 bit; sau đó - 0x80000000 sẽ đăng ký mở rộng bit đối diện. Một cách khác để suy nghĩ về nó là ban đầu, số âm là trên số dương (cách nhau bởi 0x80000000); các ^ hoán đổi vị trí của chúng; thì - thay đổi số âm xuống dưới 0.

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

+1 vì không sử dụng điều kiện. Nó có lẽ không tạo ra sự khác biệt lớn trong Python, nhưng chắc chắn nó cảm thấy thỏa mãn hơn. – zneak

0

Một giải pháp nhanh chóng và dơ bẩn (x là không bao giờ lớn hơn 32-bit trong trường hợp của tôi).

if x > 0x7fffffff: 
    x = x - 4294967296 
Các vấn đề liên quan