2010-05-05 31 views
10

Một số câu hỏi trên trang web này tiết lộ những cạm bẫy khi trộn các loại đã ký và chưa ký và hầu hết các trình biên dịch dường như thực hiện tốt công việc tạo cảnh báo loại này. Tuy nhiên, GCC dường như không quan tâm khi gán một hằng số đã ký cho một loại không dấu! Hãy xem xét các chương trình sau đây:Tại sao GCC không đưa ra cảnh báo khi gán chữ ký đã ký cho loại không dấu?

/* foo.c */ 
#include <stdio.h> 
int main(void) 
{ 
    unsigned int x=20, y=-30; 
    if (x > y) { 
     printf("%d > %d\n", x, y); 
    } else { 
     printf("%d <= %d\n", x, y); 
    } 
    return 0; 
} 

Compilation với GCC 4.2.1 như sau sản xuất không có đầu ra trên console:

gcc -Werror -Wall -Wextra -pedantic foo.c -o foo 

Kết quả là thực thi tạo đầu ra sau đây:

$ ./foo 
20 <= -30 

Is có một số lý do mà GCC không tạo ra bất kỳ cảnh báo hoặc thông báo lỗi nào khi gán giá trị đã ký -30 cho biến số nguyên không dấu y?

+3

Lưu ý rằng bạn nên sử dụng% u để in 'unsigned int'. –

+0

@ Bastien, thực sự; có lẽ thú vị hơn là, như AndreyT đã chỉ ra trong câu trả lời của mình dưới đây, 'printf ("% d ")' cho thấy giá trị đã ký thay vì giá trị chưa ký (4294967266) được sử dụng bởi toán tử so sánh! – maerics

+1

Đó là do biểu diễn bổ sung 2 của int đã ký: http://en.wikipedia.org/wiki/Two%27s_complement (biểu diễn này không được đảm bảo bởi tiêu chuẩn C, nhưng trong thực tế tôi chưa bao giờ nghe nói về một biểu diễn khác vẫn đang được sử dụng) –

Trả lời

14

Sử dụng -Wconversion:

~/src> gcc -Wconversion -Werror -Wall -Wextra -pedantic -o signwarn signwarn.c 
cc1: warnings being treated as errors 
signwarn.c: In function 'main': 
signwarn.c:5: error: negative integer implicitly converted to unsigned type 

Tôi đoán điều ở đây là gcc là thực sự khá tốt ở những cảnh báo tạo ra, nhưng nó mặc định là không làm như vậy đối với trường hợp (đôi khi bất ngờ). Bạn nên duyệt qua các cảnh báo có sẵn và chọn một tập hợp các tùy chọn tạo ra những tùy chọn mà bạn cảm thấy sẽ hữu ích. Hoặc chỉ là tất cả chúng, và đánh bóng mã đó cho đến khi nó tỏa sáng! :)

6

Khả năng chuyển đổi giá trị âm thành loại chưa ký là một đối tượng địa lý của ngôn ngữ C. Vì lý do này, cảnh báo không được phát hành theo mặc định. Bạn phải yêu cầu nó một cách rõ ràng, nếu bạn muốn.

Đối với những gì chương trình của bạn xuất ra ... Sử dụng %d định dạng thông số của printf với giá trị chưa ký nằm ngoài phạm vi loại int dẫn đến hành vi không xác định.

+0

Hey, bắt tốt. 'printf ("% d ", y);' nằm trong một thể loại hoàn toàn khác với 'y = -30;'. –

+0

Điểm tuyệt vời, tôi có thể tưởng tượng bằng cách sử dụng một giá trị âm để tạo ra một bitfield mong muốn, ví dụ. – maerics

+1

Yep - chuyển đổi số âm thành unsigned được định nghĩa để tạo ra kết quả 'modulo' kích thước của int không dấu, vì vậy (unsigned) -1 là một cách hoàn toàn tốt để nói "unsigned with all 1's in it". Khi các con số đã ký được thể hiện bằng phần bổ sung của 2, 'chuyển đổi' này chỉ đơn giản là mẫu bit giống như ký hiệu. – greggo

1

Sử dụng (chưa ký) -1 là cách thường được sử dụng để đặt tất cả bit và đôi khi được trích dẫn là lý do cho tính năng này (sai) của C, thậm chí bởi những người nên biết rõ hơn . Nó không phải là hiển nhiên cũng không phải là di động - biểu thức bạn muốn sử dụng để thiết lập tất cả các bit là ~ 0.

+0

Tôi xem xét ý nghĩa của "uint32_t x = -1;' hiển nhiên, Chuẩn xác định hành vi chính xác, và nó dễ dàng hơn là 'uint32_t x = ~ 0;' hoặc 'uint32_t x = ~ 0u;' [trên một hệ thống ký hiệu độ lớn, biểu mẫu '~ 0' sẽ đặt' x' thành 0xFFFF8001ul; trên bất kỳ hệ thống 16 bit nào, biểu mẫu '~ 0u' sẽ đặt' x' thành 0x0000FFFFul; biểu mẫu sử dụng '-1' sẽ hoạt động trên bất kỳ hệ thống nào định nghĩa 'uint32_t'.] – supercat

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