2016-07-17 38 views
6

Tôi bắt gặp câu hỏi này.Tại sao đầu ra của mã C này là "không"?

#include <stdio.h> 

int main(void) { 
    // your code goes here 
    unsigned int i = 23; 
    signed char c = -23; 

    if (i > c) 
     printf("yes"); 
    else 
     printf("no"); 

    return 0; 
} 

Tôi không thể hiểu tại sao đầu ra của mã này là no.

Ai đó có thể giúp tôi hiểu cách toán tử so sánh hoạt động khi so sánh được thực hiện giữa intchar trong C?

+4

đọc về [hai của bổ sung] (https://en.wikipedia.org/wiki/Two%27s_complement). và về [chuyển đổi ngầm trong C] (http: //en.cppreference.com/w/c/language/conversion) (đặc biệt là về [các phép chuyển đổi số học] (http://en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions)). –

+0

Nguồn kinh điển là [C standard] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) (đó là bản nháp N1570). Xem 6.3.1.1 cho các quảng cáo * số nguyên * (chuyển đổi giá trị 'char char' thành' int') và 6.3.1.8 cho * chuyển đổi số học thông thường * (chuyển đổi cả hai toán hạng thành kiểu chung, 'unsigned int' , trước khi thực hiện so sánh). –

Trả lời

11

Bạn đang so sánh số unsigned int với số signed char. Các ngữ nghĩa của loại so sánh này phản trực giác: hầu hết các phép toán nhị phân liên quan đến các toán hạng signedunsigned được thực hiện trên các toán hạng chưa ký, sau khi chuyển đổi giá trị đã ký thành unsigned (nếu cả hai toán hạng có cùng kích thước sau khi quảng bá). Dưới đây là các bước:

  • Giá trị signed char được đề bạt lên một int với cùng giá trị -23.
  • so sánh sẽ được thực hiện trên intunsigned int, loại thông thường là unsigned int như được xác định trong tiêu chuẩn C.
  • int được chuyển đổi thành unsigned int với giá trị UINT_MAX - 23, một số rất lớn.
  • So sánh được thực hiện trên các giá trị unsigned int: 23 là giá trị nhỏ hơn, so sánh sẽ được tính là sai.
  • Chi nhánh else được đánh giá, no được in.

Để làm cho vấn đề tồi tệ hơn, nếu c đã được định nghĩa là một long, kết quả sẽ phụ thuộc vào việc longint có cùng kích thước hay không. Trên Windows, nó sẽ in no, trong khi trên Linux 64 bit, nó sẽ in yes.

Không bao giờ trộn các giá trị đã ký và chưa ký trong so sánh. Bật cảnh báo trình biên dịch để ngăn chặn loại lỗi này (-Wall hoặc -Weverything). Bạn cũng có thể làm cho tất cả các cảnh báo này gây tử vong với -Werror để tránh hoàn toàn loại mã bị lỗi này.

Đối với một tài liệu tham khảo đầy đủ, đọc phần sau của C chuẩn (C11) thuộc 6.3 Chuyển đổi:

  • chương trình khuyến mãi nguyên được giải thích trong 6.3.1.1 Boolean, ký tự, và số nguyên .
  • chuyển đổi toán hạng được mô tả chi tiết trong 6.3.1.8 Chuyển đổi số học thông thường.

Bạn có thể tải dự thảo mới nhất của tiêu chuẩn C11 từ trang web của nhóm công tác: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

+0

Tham khảo hữu ích dưới dạng bổ sung cho câu trả lời này: https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+rules – chrphb

+0

Và 6.3.1.1 cho các chương trình khuyến mãi * số nguyên *. [Đây là một liên kết] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) với bản nháp N1570 của tiêu chuẩn C11. –

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