2009-06-21 9 views
8

Tôi đã quét một mã nguồn của bên thứ ba sử dụng FindBugs (chỉ cần phải thận trọng trước khi tích hợp vào nó mỏ), và tìm thấy các cảnh báo sau đây:Cảnh báo Findbugs: Chuyển số nguyên theo 32 - nghĩa là gì?

long a = b << 32 | c 

Bug: Integer thay đổi bởi id 32 Pattern: ICAST_BAD_SHIFT_AMOUNT , loại: BSHIFT, danh mục: CORRECTNESS

Mã thực hiện thay đổi số nguyên số không đổi ngoài phạm vi 0..31. Hiệu quả của việc này là sử dụng 5 bit thấp hơn của giá trị số nguyên để quyết định mức độ thay đổi theo. Điều này có thể là không mong muốn và ít nhất là khó hiểu.

Có ai vui lòng giải thích chính xác ý nghĩa của điều trên không?

Cảm ơn! (Tôi là một người mới trong lập trình Java)

Trả lời

30

Từ Java Language Specification:

Nếu kiểu thúc đẩy của toán hạng bên trái là int, chỉ có năm bit thấp nhất theo đơn đặt hàng của toán hạng bên phải được sử dụng như là khoảng cách dịch chuyển. Nó giống như toán hạng bên phải đã phải chịu một toán tử AND logic logic & (§15.22.1) với giá trị mặt nạ 0x1f. Khoảng cách dịch chuyển thực sự được sử dụng do đó luôn nằm trong khoảng từ 0 đến 31, bao gồm.

Vì vậy, nếu b là một int, khái niệm giống hệt

long a = b | c; 

mà tôi rất nghi ngờ là những gì được dự định. Có lẽ nó phải là

long a = ((long) b << 32) | c; 

(Nếu b đã lâu rồi, mã đúng và FindBugs bị nhầm lẫn về lỗi).

+0

Vì vậy,' int >> 32 (0x100000) == int >> 0 (0x00000) '? –

+1

Cú pháp giả ngẫu nhiên bạn sử dụng, nhưng có, đúng vậy. – UndefinedBehavior

5

Đã chỉnh sửa: Vấn đề gần như chắc chắn xuất phát từ thực tế là 'b' là 'int' chứ không phải 'dài'. Trong C, nếu 'b' là số nguyên thay vì dài và bạn chuyển sang trái 32 bit, tất cả các bit từ giá trị ban đầu đã bị xóa, do đó kết quả của biểu thức tổng thể sẽ giống như 'c' bạn sẽ gọi hành vi không xác định, vì vậy bất kỳ kết quả nào đều được phép. Java định nghĩa mọi thứ khác nhau - như đã lưu ý trong nhận xét của Rasmus Faber và câu trả lời đã chọn - và làm thay đổi quá nhiều modulo số bit tối đa có thể được dịch chuyển. [Có vẻ như một cách kỳ lạ để làm kinh doanh; Tôi có thể đã sắp xếp cho một ngoại lệ trong một ngôn ngữ có chúng. Tuy nhiên, nó được xác định rõ ràng, đó là quan trọng hơn chính xác những gì định nghĩa được.] Việc ép buộc 64-bit không xảy ra trong khi biểu thức được đánh giá; nó xảy ra khi biểu thức hoàn thành và nhiệm vụ diễn ra.

Tham chiếu đến 5 bit là ... hấp dẫn. Nó có nghĩa là nếu bạn dịch chuyển sang trái, ví dụ, 48, hoặc nhị phân 110000, nó giống như dịch chuyển sang trái bằng 16. Hoặc, cách khác, 'x << n' giống như 'x << (n % 32)'.

+1

D'oh, bạn nói đúng, đã xóa câu trả lời của tôi và cập nhật của bạn :) –

+1

Phần đầu tiên của câu trả lời là không chính xác. Trong Jave, b << 32 là b, không phải bằng không. Tuy nhiên, paragraåh thứ hai là chính xác. –

+1

Hiệu chỉnh: Trong hành vi C là _undefined_ khi dịch chuyển một giá trị với đối số bên ngoài phạm vi [0, typewidth - 1]. Ví dụ các trình biên dịch opencl từ nvidia và intel mang lại cho tôi những hành vi khác nhau cho biểu thức 'b >> 32'. – notso