Khi các tiêu chuẩn C được mã hóa, các nền tảng khác nhau sẽ làm những việc khác nhau khi các số nguyên âm chuyển dịch trái. Trên một số người trong số họ, hành vi có thể kích hoạt bẫy thực hiện cụ thể mà hành vi của họ có thể nằm ngoài tầm kiểm soát của chương trình và có thể bao gồm việc thực thi mã ngẫu nhiên. Tuy nhiên, có thể các chương trình được viết cho các nền tảng như vậy có thể sử dụng các hành vi như vậy (một chương trình có thể chỉ định rằng người dùng sẽ phải làm gì đó để cấu hình trình xử lý bẫy của hệ thống trước khi chạy nó, nhưng sau đó chương trình có thể khai thác hành vi của các trình xử lý bẫy được cấu hình phù hợp). Các tác giả của tiêu chuẩn C không muốn nói rằng các trình biên dịch cho các máy nơi dịch chuyển trái của các số âm sẽ bẫy phải được sửa đổi để ngăn chặn bẫy như vậy (vì các chương trình có khả năng dựa vào nó), nhưng nếu trái- chuyển số âm được phép kích hoạt bẫy có thể gây ra bất kỳ hành vi tùy ý nào (bao gồm cả việc thực thi mã ngẫu nhiên) có nghĩa là việc dịch chuyển trái một số âm được phép làm bất cứ điều gì. Do đó hành vi không xác định. Trong thực tế, cho đến khoảng 5 năm trước, 99%% trình biên dịch được viết cho một máy sử dụng toán học bù hai (nghĩa là 99%% máy được tạo từ năm 1990) sẽ mang lại các hành vi sau đây cho x<<y
và x>>y
, trong chừng mực mà sự phụ thuộc mã vào hành vi như vậy được coi là không di chuyển nhiều hơn mã được giả định là char
là 8 bit. Tiêu chuẩn C không ủy thác hành vi như vậy, nhưng bất kỳ tác giả trình biên dịch nào muốn tương thích với một cơ sở rộng lớn của mã hiện có sẽ tuân theo nó.
- nếu
y
là một loại ký, x << y
và x >> y
được đánh giá là mặc dù y
được đúc để unsigned.
- nếu
x
là loại int
, x<<y
tương đương với (int)((unsigned)x << y)
.
- nếu
x
là loại int
và tích cực, x>>y
tương đương với (unsigned)x >> y
. Nếu x
thuộc loại int
và âm, x>>y
tương đương với `~ (~ ((chưa ký) x) >> y).
- Nếu
x
thuộc loại long
, các quy tắc tương tự được áp dụng, nhưng với unsigned long
thay vì unsigned
.
- nếu
x
là một loại N-bit và y
lớn hơn N-1, sau đó x >> y
và x << y
có thể tùy tiện mang lại không, hoặc có thể hành động như thể các toán hạng bên phải là y % N
; chúng có thể yêu cầu thêm thời gian tỷ lệ thuận với y
[lưu ý rằng trên máy 32 bit, nếu y
là âm, có khả năng là thời gian dài, mặc dù tôi chỉ biết một máy thực tế chạy hơn 256 bước bổ sung ]. Các trình biên dịch không nhất quán trong sự lựa chọn của chúng, nhưng sẽ luôn trả về một trong các giá trị được chỉ định mà không có các tác dụng phụ khác.
Thật không may vì một lý do nào đó tôi không thể hiểu được, các nhà biên dịch đã quyết định thay vì cho phép lập trình viên chỉ ra những trình biên dịch giả định nào nên sử dụng để xóa mã chết, trình biên dịch sẽ không thể thực hiện bất kỳ thay đổi nào hành vi của họ không được bắt buộc bởi tiêu chuẩn C. đang do đó, được đưa ra như sau:
uint32_t shiftleft(uint32_t v, uint8_t n)
{
if (n >= 32)
v=0;
return v<<n;
}
một trình biên dịch có thể xác định rằng vì mã sẽ tham gia vào các hành vi undefined khi n là 32 hoặc lớn hơn, trình biên dịch có thể giả định rằng if
sẽ không bao giờ trở thành sự thật, và có thể vì thế bỏ qua mã. Do đó, trừ khi hoặc cho đến khi một người nào đó đưa ra tiêu chuẩn cho C để khôi phục các hành vi kinh điển và cho phép các lập trình viên chỉ định những giả định nào đã loại bỏ mã chết, các cấu trúc như vậy không thể được đề xuất cho bất kỳ mã nào có thể được cung cấp cho trình biên dịch siêu hiện đại.
Phần nào không rõ ràng? * Nếu * E1 có giá trị không âm và ... * nếu không * hành vi không xác định. E1 có giá trị âm, do đó hành vi không xác định. Đúng là đôi khi người tiêu chuẩn có thể làm với một số dấu ngoặc phụ để làm cho nó hoàn toàn rõ ràng "khác" là gì, nhưng ở đây có nghĩa là "trong mọi tình huống chưa được mô tả". Nó giúp khi giải thích những điều này để nhớ rằng trong * bất kỳ * tình huống mà tiêu chuẩn không mô tả hành vi, sau đó hành vi là không xác định. Vì vậy, trong thực tế rằng "nếu không" là chính thức dự phòng. –
@SteveJessop: Tôi nghĩ __otherwise__ có nghĩa là nếu giá trị không thể biểu diễn thì hành vi không xác định. Tôi không chắc chắn nếu điều này bao gồm E1 với giá trị âm. – user103214
@Norman: Đúng vậy, hãy xem câu trả lời của R.Marthinho, có một dấu chấm phẩy, một người seperator rõ ràng giữa điều kiện và kết quả cuối cùng. – Xeo