2013-01-07 31 views
12

Khi thêm một số int32 vào số 642 bit native int, CLR có được gia hạn hoặc không mở rộng số nguyên 32 bit không? Và quan trọng nhất: dựa trên thông tin nào nó đưa ra lựa chọn này?Kết quả của việc thêm int32 vào một int gốc 64 bit?


Tôi viết một trình biên dịch NET và đã đọc đặc tả ECMA kỹ lưỡng, nhưng không thể tìm thấy câu trả lời.

CLI chỉ hỗ trợ một tập hợp con của các loại trong các hoạt động của nó đối với các giá trị được lưu trữ trên stack đánh giá của nó: int32, int64, và native int.
-ECMA 335, Mục I 12.1: Hỗ trợ các kiểu dữ liệu

Kể từ khi giá trị trên stack đánh giá không có thông tin về signedness của họ, hướng dẫn mà signedness của toán hạng quan trọng có hai phiên bản: một cho đã ký và một cho số nguyên chưa ký. Các hướng dẫn add, submul (những người không kiểm tra tràn) không cần phải quan tâm đến sự ký kết của toán hạng miễn là toán hạng có cùng kích thước và do đó chỉ có một biến thể. Tuy nhiên, các toán hạng không phải lúc nào cùng kích thước ...

ECMA 335, Mục III 1.5: Operand loại bảng khẳng định rằng một int32native int có thể được thêm vào, trừ, nhân và chia. Kết quả lại một lần nữa là native int. Trên hệ thống 64 bit, native int rộng 64 bit.

ldc.i4.0   // Load int32 0 
conv.i    // Convert to (64-bit) native int 
ldc.i4.m1   // Load int32 -1 
add     // Add native int 0 and int32 0xFFFFFFFF together 

Vậy kết quả ở đây là gì? Lưu ý rằng, theo đặc điểm kỹ thuật, thời gian chạy không cần phải theo dõi các loại chính xác hoặc ký kết của các giá trị trên ngăn xếp: chỉ biết int32, int64native int (và một số khác không có liên quan ở đây).


Tôi tưởng tượng rằng IntPtrUIntPtr số học, vì nó trong nội bộ được biểu diễn như ints bản xứ, sẽ cũng sử dụng loại này bổ sung. Tuy nhiên, ILSpy cho thấy thêm một số IntPtrInt32 trong C# gọi toán tử + bị quá tải trên lớp IntPtr, chỉ chấp nhận đối số Int32 đã ký.

Thực hiện trực tiếp trong CIL (sử dụng hướng dẫn add) cũng cho biết rằng số nguyên được hiểu là đã được ký. Nó cũng đã được thực hiện trong Mono, nhưng tôi không thể tìm thấy bất kỳ tài liệu tham khảo để trở lại những phát hiện của tôi lên.

+0

Dấu hiệu cho giá trị được thăng hạng sẽ không bị phát hiện. Xem thông tin này để biết các giải pháp khả thi (dành cho Mac nhưng điều đó không quan trọng trong trường hợp này): https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/64bitPorting/MakingCode64-BitClean/MakingCode64- BitClean.html – K3N

Trả lời

5

Ký kết không quan trọng khi thêm hai giá trị của cùng một bit. Ví dụ, thêm 32-bit -10 (0xfffffff6) vào 32-bit 10 (0x0000000a) sẽ cho kết quả chính xác 0. Do đó, chỉ có một lệnh add trong CIL (Ngôn ngữ Hướng dẫn Chung).

Tuy nhiên, khi thêm hai giá trị của các bit khác nhau, thì ký hiệu thực hiện. Ví dụ, thêm 32-bit -10 đến 64-bit 10 có thể dẫn đến 4294967296 (0x100000000) khi thực hiện unsigned, và 0 khi đã ký.

Các CIL add hướng dẫn cho phép thêm một số nguyên mẹ đẻ32-bit số nguyên. Số nguyên gốc có thể là 64 bit (trên hệ thống 64 bit). Kiểm tra cho thấy rằng add xử lý số nguyên 32 bit làm số nguyên đã ký và mở rộng ký hiệu.This is not always correct và có thể được xem là a bug. Microsoft hiện không sửa chữa nó.

Vì kiểm tra tràn phụ thuộc vào việc toán hạng được coi là chưa ký hoặc ký, có hai biến thể của add.ovf: add.ovf (đã ký) và add.ovf.un (chưa ký). Tuy nhiên, các biến thể này cũng chính xác mở rộng ký hiệu bằng cách không mở rộng toán hạng nhỏ hơn khi thêm một số nguyên 32 bit vào một số nguyên gốc.

Vì vậy, việc thêm số nguyên gốc và số nguyên 32 bit không dấu có thể mang lại kết quả khác nhau tùy thuộc vào cài đặt kiểm tra tràn của C#. Rõ ràng một thực tế là tôi không thể tìm ra điều này là kết quả của một lỗi hoặc giám sát trong thiết kế ngôn ngữ CIL.

2

Bạn đang ở trong lãnh thổ chưa được khám phá ở đây, tôi không biết bất kỳ ngôn ngữ .NET nào thực sự cho phép điều này. Trình kiểm tra cú pháp của họ từ chối bất kỳ mã nào cố gắng thực hiện điều này. Ngay cả việc thêm hai int nội bộ cũng bị từ chối. Cuối cùng nó là đến jitter để tạo ra các mã máy cho nó. Nếu bạn muốn biết điều gì xảy ra thì chỉ cần thử nghiệm. Hãy chắc chắn để kiểm tra ít nhất là x86 và x64 jitters.

Với ngữ nghĩa iffy và khả năng thực sự thay đổi jitter trong tương lai có thể phá vỡ các giả định của bạn, tôi thực sự khuyên bạn cũng nên từ chối ngôn ngữ này.Nó chỉ không phải là rất hữu ích và một workaround đơn giản mà phôi đến (dài) và kết quả trở lại (IntPtr) đã được định nghĩa tốt ngữ nghĩa. Mà chính nó là một cách để có được hành vi dự đoán được trong bộ tạo mã của riêng bạn.

+0

Tôi đã thêm một số thông tin vào bài đăng: C# sử dụng toán tử cộng chồng quá tải khi thêm 'IntPtr' vào' Int32'. Trong CIL, lệnh 'add' có vẻ giải thích' Int32' như đã ký. Tuy nhiên, tôi không biết tại sao. – Virtlink

Các vấn đề liên quan