2010-03-08 35 views
20

Có vẻ như tôi sẽ có thể thực hiện thay đổi bit trong C/C++ bởi hơn 32 bit cung cấp toán hạng bên trái của ca làm việc là dài. Nhưng điều này dường như không hoạt động, ít nhất là với trình biên dịch g ++.Làm cách nào để bit chuyển đổi dài hơn 32 bit?

Ví dụ:

unsigned long A = (1L << 37) 

cho

A = 0 

mà không phải là những gì tôi muốn. Tôi có thiếu cái gì đó hay chỉ là điều này không thể?

-J

+2

Long là 32 bit trên hầu hết các kiến ​​trúc .... –

+0

Sử dụng 'LL' thay vì chỉ' L' –

Trả lời

11

Tái thử này sử dụng một biến kiểu uint64_t (từ stdint.h) thay vì long. uint64_t được đảm bảo dài 64 bit và sẽ hoạt động như bạn mong đợi.

+4

Nếu 'long' là 32 bit thì' (1L << 37) 'sẽ bằng không phụ thuộc vào loại biến. '1' cũng phải được truyền tới kiểu đích. – Potatoswatter

+7

@Potatoswatter: Nếu 'long' là 32 bit thì hành vi là ** không xác định ** cho các thay đổi từ 32 bit trở lên. Trên thực tế, trên GCC/x86, '1L << 37 == 32'. Tương tự cho GCC/PowerPC. (Điều gì đang xảy ra là shifter chỉ nhận được năm bit thấp.) –

+1

@Dietrich: True. Quan điểm của tôi (mà tôi dường như cũng bị bỏ rơi trong trạng thái) là biểu hiện mà anh ta có thể muốn là '1LL << 37'. – Potatoswatter

9

Vâng, nó phụ thuộc vào kích thước thực tế của các loại long (chính xác hơn, nó rộng theo bit). Nhiều khả năng trên nền tảng của bạn long có chiều rộng là 32 bit, do đó bạn nhận được 0 là kết quả (cũng có thể xem P.S. bên dưới). Sử dụng loại lớn hơn. long long có thể?

P.S. Lưu ý bổ sung, chuyển một loại bằng nhiều bit hơn chiều rộng (hoặc số bit bằng nhau) tạo ra hành vi không xác định bằng C và C++ (C++ sử dụng cụm từ chiều dài thay vì chiều rộng). Vì vậy, bạn đang không được bảo đảm để có được 0 từ không 1L << 37 cũng không 1L << 32 trên một nền tảng nơi long có chiều rộng 32.

+0

phải, lý do sẽ được rằng trong một số CPU hướng dẫn thay đổi sẽ chỉ nhìn vào các bit thấp và trình biên dịch C được phép sao chép hành vi này.Vì vậy, (i << 37) trên một int 32-bit có thể giống như (i << 5). Khóa học "hành vi không xác định" có nghĩa là nó có thể làm bất cứ điều gì hoàn toàn, nhưng điều này có thể là hành vi "quan sát" khác ngoài việc trở về 0. –

+0

@Ben Voigt: Chính xác. Hơn nữa, đây là một trong những ví dụ của UB thực sự thể hiện trong thực tế. Trên phần cứng như vậy thường có thể nhận thấy rằng, ví dụ, 'int i = 5; i << = 37; 'tạo ra kết quả khác nhau từ' int i = (5 << 37); ', vì trước đây được tính toán bởi CPU tại thời gian chạy và sau đó - bởi trình biên dịch tại thời gian biên dịch. – AnT

26

A là bằng 0 vì A chỉ có 32-bit, vì vậy tất nhiên bạn đang chuyển hướng tất cả các bit tắt bên trái chỉ còn 0 bit. Bạn cần phải thực hiện một phiên bản 64-bit:

unsigned long long A = (1ULL << 37); 

Hoặc nếu bạn có ý định sử dụng Visual C++:

unsigned __int64 A = (1ULL << 37); 
+0

Tôi đoán tôi đã quen với Java, nơi được bảo đảm dài 64 bit. Nếu nó chỉ 32 bit, nó khác với một int như thế nào? –

+3

Để làm cho mọi thứ rõ ràng hơn một chút, tôi muốn làm rõ điều gì đó. Kích cỡ của kiểu chữ C, ngắn, int, dài, dài thay đổi tùy thuộc vào kiến ​​trúc và trình biên dịch máy. Tuy nhiên, tiêu chuẩn C đảm bảo mối quan hệ này: sizeof (char) <= sizeof (ngắn) <= sizeof (int) <= sizeof (dài) <= sizeof (long long) Nhưng đối với các máy 32 bit điển hình , có lẽ là những gì bạn đang biên soạn, kích thước cho char, ngắn, int, dài và dài là 8, 16, 32, 32 & 64 bit tương ứng. – Cthutu

+5

Một nhận xét pedantic: C tiêu chuẩn không đảm bảo rằng. C + + tiêu chuẩn không. C tiêu chuẩn nói rằng 'phạm vi của char <= phạm vi ngắn <= phạm vi của int <= phạm vi dài <= phạm vi dài dài', nhưng nó không nói gì về' sizeof'. Chính thức, mối quan hệ cho 'sizeof' có thể không giữ trong C, mặc dù đó sẽ là một điều rất kỳ lạ và kỳ lạ để xem. – AnT

2

Bạn có chắc chắn rằng dài 64 bit với hệ điều hành và trình biên dịch cụ thể của bạn không? Sử dụng stdint.h và thử nó như sau:

#include <stdint.h> 

uint64_t x = (1ULL << 37); 
0

Mới C++ tiêu chuẩn giới thiệu các hậu tố LL và ULL cho các chữ số nguyên. Bạn có thể thử sử dụng chúng vì tất cả các trình biên dịch mới nhất đều hỗ trợ chúng. Nhưng bạn nên biết rằng nó không phải là một phần của tiêu chuẩn C++ hiện hành.

long long A = (1LL << 37) 
0

Trong trường hợp của bạn, bạn bị giới hạn ở các loại cơ sở ngôn ngữ. Một giải pháp chung cho các số nguyên có kích thước tùy ý [quasi] là sử dụng Integer lớp dưới Crypto++.

-1

Bạn có đối số được đảo ngược.

unsigned long A1 = (1L << 37); // is 2 to the 37th 
unsigned long A = (37UL<<1UL); // has just multiplied 37 by 2 
+0

Tại sao bạn nghĩ rằng họ muốn 37 * 2? Không có một chút nhỏ bé mà đó là mục tiêu trong câu hỏi. – ShadowRanger

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