2010-10-22 5 views

Trả lời

6

Đã điểm khởi đầu của bạn là có vấn đề:

char c = 0x80; 

Nếu (như dường như trong trường hợp của bạn) char là một loại ký, bạn đang giao hằng số nguyên 128 cho một kiểu duy nhất là bảo đảm để giữ giá trị lên đến 127. Trình biên dịch của bạn sau đó có thể chọn cung cấp cho bạn một số giá trị được xác định thực hiện (-128 trong trường hợp của bạn mà tôi đoán) hoặc phát hành một lỗi phạm vi.

Sau đó, bạn đang thực hiện một thay đổi trái trên giá trị âm đó. Điều này mang lại hành vi không xác định. Trong tổng số bạn có một vài thực hiện được xác định lựa chọn cộng với hành vi không xác định để xác định kết quả:

  • signedness của char
  • lựa chọn như thế nào để chuyển đổi 128 để signed char
  • chiều rộng của char
  • đại diện dấu của int (có ba khả năng)
  • lựa chọn về cách triển khai (hoặc không) chuyển trái trên tiêu cực int

Có thể là một bài tập tốt để bạn tra cứu tất cả các trường hợp này để xem kết quả khác nhau có thể là gì.

Nói tóm lại một số kiến ​​nghị:

  • chọn một hằng số thích hợp để khởi tạo một biến
  • không làm phép tính với đồng bằng char
  • không làm trái sự thay đổi đối với các loại ký
+0

Thanku Jens sir cho câu trả lời ur. –

+0

Đoạn đầu tiên của lời giải thích là sai và có thể đánh lừa người thiếu kinh nghiệm. "char c = 0x80;" là tốt giống như "int c = 0xFFFFFFFF" là tốt, nhưng phần đó là không tốt là giả định 0x80 sẽ là 128 khi char có thể được ký (phạm vi -128 đến 127, không 0 đến 255) –

+0

@ B.Nadolson , Tôi không nghĩ rằng nó gây hiểu lầm. Hằng số '0x80' là kiểu' int' và có giá trị '128'.Loại và giá trị này trên RHS được xác định trước, và sau đó loại và giá trị đó được chuyển đổi để phù hợp với loại trên LHS. Cố gắng khởi tạo biến có thể được ký với giá trị không phù hợp với loại là lỗi ngữ nghĩa. –

18

char có thể được ký trên nền tảng của bạn, trong trường hợp này 0x80 đại diện -128 (giả định bổ sung hai).

Khi số char được sử dụng làm toán hạng với toán tử <<, nó được thăng cấp thành int (vẫn -128). Vì vậy, khi bạn áp dụng dịch chuyển trái, bạn sẽ nhận được -256. Về mặt kỹ thuật, thay đổi giá trị âm là được xác định thực hiện không xác định, nhưng những gì bạn thấy là hành vi điển hình.

+0

Tôi không nghĩ tuyên bố của bạn về quảng cáo 'int' là chính xác. Các toán tử Shift không thực hiện quảng cáo, loại kết quả là loại ở bên trái. –

+0

@ Jens: Để công bằng, tôi chỉ có tiêu chuẩn C99 trước mặt mình. Nhưng nó nói trong phần 6.5.7: "Các chương trình khuyến mãi số nguyên được thực hiện trên mỗi toán hạng." –

+0

oops, phải. Vì vậy, tôi sẽ tích hợp đó trong câu trả lời của tôi, quá :) –

3

c được gán 0x80. Giả sử byte 8 bit, giá trị của nó trong biểu diễn nhị phân, là 10000000. Rõ ràng, trên nền tảng của bạn, char là loại đã ký. Vì vậy, 0x80 (ví dụ: 10000000) tương ứng với -128.

Khi << được áp dụng cho giá trị char, nó được thăng cấp thành int và biển báo được giữ nguyên. Vì vậy, khi chuyển một lần sang trái, với số nguyên 32 bit, nó sẽ trở thành 11111111111111111111111100000000 (bổ sung hai) là -256.

+0

Quảng bá cho 'int' không liên quan gì đến' printf' trong trường hợp này; đó là do '<<'. Ngoài ra, đó không phải là đại diện của -256 trong bổ sung của một hoặc hai. –

+0

@Oli Cảm ơn bạn đã sửa. –

+0

Cảm ơn bạn rất nhiều Oli và Sinan.Tôi đã hiểu được logic .. –

0

Tôi tự hỏi tại sao trình biên dịch của bạn không phàn nàn với cảnh báo rằng 0x80 không phù hợp với char, mà trên nền tảng của bạn chỉ có thể đại diện cho các giá trị từ -0x80 đến 0x7F.

Hãy thử đoạn mã này:

#include <stdio.h> 
#include <limits.h> 
#include <stdlib.h> 

int main() { 
     printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX); 
     return EXIT_SUCCESS; 
} 

tình hình của bạn được gọi là tràn.

1

Chỉ cần ghi chú bên. Từ góc nhìn từ dưới lên, thay đổi bit (và mặt nạ) được dựa trên độ dài từ của kiến ​​trúc (được biểu diễn bằng bit). Độ dài của một từ, thay đổi từ kiến ​​trúc đến kiến ​​trúc.

See this Wiki page for word lengths by architecture

Nếu ai biết độ dài lời của kiến ​​trúc đích, người ta có thể sử dụng bit chuyển sang nhân lên, và phân chia (trong một số trường hợp), nhanh hơn so với sử dụng toán hạng.

See this Wiki page for interesting diagrams of bit-shifting

Kể từ khi bit mã-chuyển là kiến ​​trúc phụ thuộc, người ta không thể giả định một phần cụ thể của mã bit chuyển sẽ làm việc theo cách tương tự từ kiến ​​trúc đến kiến ​​trúc. Tuy nhiên, một khi đã quen thuộc với ý tưởng về độ dài từ khác nhau cho các kiến ​​trúc khác nhau, việc dịch chuyển bit trở nên ít bí ẩn và dễ dự đoán hơn.

Rất may, hôm nay chúng tôi có độ dài từ 8, 16, 32 và 64 bit và độ dài ký tự 8 bit. Trong những ngày của máy tính cổ, một kiến ​​trúc có thể có độ dài từ 12, hoặc 15 hoặc 23 bit (v.v., quảng cáo nauseum).

+0

Thanku Mike sir để chia sẻ thông tin này.Bạn đều có kiến ​​thức tuyệt vời. –