2013-03-25 43 views
13

Tôi có đơn giản C++ mã sau:Visual C++ 2010: Tại sao "không khớp/unsigned không khớp" biến mất nếu tôi thêm "const" vào một so sánh?

#include "stdafx.h" 
int main() 
{ 
    int a = -10; 
    unsigned int b = 10; 
    // Trivial error is placed here on purpose to trigger a warning. 
    if(a < b) { 
     printf("Error in line above: this will not be printed\n"); 
    } 
    return 0; 
} 

Biên soạn sử dụng Visual Studio 2010 (mặc định C++ console ứng dụng) nó mang lại cho warning C4018: '<' : signed/unsigned mismatch" on line 7như mong đợi (mã có một lỗi logic).

Nhưng nếu tôi thay đổi unsigned int b = 10; thành cảnh báo const unsigned int b = 10; biến mất! Có bất kỳ lý do đã biết nào cho hành vi đó không? gcc hiển thị cảnh báo bất kể const.

Cập nhật

tôi có thể nhìn thấy từ ý kiến ​​mà nhiều người đề nghị "nó chỉ đã được tối ưu hóa bằng cách nào đó để mà không cảnh báo cần thiết". Thật không may, cần cảnh báo vì mẫu mã của tôi có lỗi logic thực tế được đặt cẩn thận để kích hoạt cảnh báo: tuyên bố printsẽ không được gọi là bất kể số -10 thực sự nhỏ hơn 10. Lỗi này được biết đến và "cảnh báo đã ký/chưa ký" được nâng lên chính xác để tìm các lỗi như vậy.

Cập nhật

Tôi cũng có thể nhìn thấy từ ý kiến ​​mà rất nhiều người dân đã "tìm thấy" một ký/lỗi logic unsigned trong mã của tôi và được giải thích nó. Trường hợp không cần phải làm như vậy - lỗi này được đặt hoàn toàn để kích hoạt cảnh báo, là tầm thường (-10 được chuyển thành (unsigned int)-100xFFFFFFFF-10) và câu hỏi không phải là về nó :).

+5

Nghe giống như lỗi trình biên dịch. Nó có thể được tối ưu hóa biến, vì vậy bạn chỉ có 'a <10'. – AlchemicalApples

+3

@DBRalir: không, đợi đã, đúng rồi! một biến 'const' của kiểu số nguyên được khởi tạo với biểu thức hằng số biên dịch-thời gian ... nó _is_' a <10'. –

+0

trên gcc 4.4 nó không hiển thị bất kỳ cảnh báo nào với const hoặc không có const –

Trả lời

9

Đây là lỗi của Visual Studio, nhưng hãy bắt đầu bằng các khía cạnh không phải là lỗi.

Mục 5, Chú giải 9 của then applicable C++ standard đầu tiên thảo luận về những việc cần làm nếu các toán hạng là độ rộng chút khác nhau, trước khi tiếp tục phải làm gì nếu họ đều giống nhau nhưng khác nhau về dấu:

.. Nếu không, nếu toán hạng có loại số nguyên không dấu có xếp hạng lớn hơn hoặc bằng cấp bậc của loại toán hạng khác, toán hạng với loại số nguyên đã ký phải được chuyển thành loại toán hạng với số nguyên không dấu kiểu.

Đây là nơi chúng tôi biết rằng so sánh phải hoạt động với số học chưa ký. Bây giờ chúng ta cần tìm hiểu ý nghĩa của giá trị -10.

phần 4.6 cho chúng ta biết:

Nếu loại đích là unsigned, giá trị kết quả là ít nhất unsigned integer đồng dư với số nguyên nguồn (modulo 2 n trong đó n là số bit được sử dụng để đại diện cho loại unsigned). [Lưu ý: Trong đại diện bổ sung của hai, chuyển đổi này là khái niệm và không có thay đổi về mẫu bit (nếu không có cắt ngắn).- lưu ý cuối cùng] 3 Nếu loại đích được ký, giá trị không thay đổi nếu nó có thể được thể hiện trong loại đích (và chiều rộng bit); nếu không, giá trị được thực hiện.

Như bạn có thể thấy, một giá trị cụ khá cao (4294967286, hoặc 0xFFFFFFF6, giả sử unsigned int là một số 32-bit) được so sánh với 10, và do đó đảm bảo tiêu chuẩn mà printf thực sự không bao giờ gọi.

Bây giờ bạn có thể tin rằng không có quy tắc nào trong tiêu chuẩn yêu cầu chẩn đoán trong trường hợp này, do đó trình biên dịch không có vấn đề gì. (Trên thực tế, một số người viết -1 với ý định sản xuất một tất cả-những mẫu bit. Những người khác sử dụng int cho mảng lặp lại, mà kết quả trong ký/so sánh unsigned giữa size_tint. Xấu xí, nhưng được bảo đảm để biên dịch.)

Bây giờ Visual Studio ban hành một số cảnh báo "tự nguyện".

Điều này dẫn đến một cảnh báo đã được thiết lập mặc định (mức 3):

int a = -10; 
unsigned int b = 10; 
if(a < b) // C4018 
{ 
    printf("Error in line above: this will not be printed\n"); 
} 

Sau đây đòi hỏi /W4 để có được một cảnh báo. Lưu ý rằng cảnh báo đã được phân loại lại. Nó đã thay đổi từ cảnh báo C4018 thành cảnh báo C4245. Điều này rõ ràng là do thiết kế. Một lỗi logic phá vỡ một so sánh gần như luôn luôn là ít nguy hiểm hơn so với một trong đó xuất hiện để làm việc với các so sánh tích cực tích cực nhưng phá vỡ với những người tiêu cực tích cực.

const int a = -10; 
unsigned int b = 10; 
if(a < b) // C4245 
{ 
    printf("Error in line above: this will not be printed\n"); 
} 

Nhưng trường hợp của bạn là chưa khác nhau:

int a = -10; 
const unsigned int b = 10; 
if(a < b) // no warning 
{ 
    printf("Error in line above: this will not be printed\n"); 
} 

Và không có cảnh báo nào. (Vâng, bạn nên thử lại với -Wall nếu bạn muốn chắc chắn.) Đây là một lỗi. Microsoft says về nó:

Cảm ơn bạn đã gửi phản hồi này. Đây là trường hợp mà chúng tôi sẽ phát ra cảnh báo C4018. Rất tiếc, vấn đề cụ thể này là không phải là mức độ ưu tiên đủ cao để khắc phục trong bản phát hành tiếp theo cho các tài nguyên mà chúng tôi có sẵn.

Hết sức tò mò, tôi đã kiểm tra bằng Visual Studio 2012 SP1 và lỗi vẫn ở đó - không cảnh báo với -Wall.

+0

Bạn có lẽ đúng về điều đó '-1', tôi nghĩ rằng tôi đã làm điều đó bản thân mình. Nó sẽ có ý nghĩa hơn để sử dụng '~ 0' mặc dù. –

+0

@MarkRansom: vấn đề lý thuyết với '~ 0' là nó có kiểu' int', và hành vi và giá trị của nó phụ thuộc vào biểu diễn được ký. Rõ ràng trong thực tế mọi thứ đều sử dụng phần bù 2 và vì vậy '~ 0 == -1'. Nếu bạn muốn tối ưu hóa tối đa một loại không dấu (không lặp lại tên của loại hoặc sử dụng 'decltype'), thì bạn cần gán' -1' hoặc '~ 0U'. Sử dụng '-1' để nhấn mạnh rằng các kiểu unsigned là modul số học' 2^n', và '~ 0U' để nhấn mạnh rằng các kiểu unsigned là bitfields. –

+0

Rất tiếc, tôi phải nói sử dụng '~ 0ULL' trong nhận xét của tôi ở trên, vì tất nhiên' ~ 0U' không thành công nếu loại đích lớn hơn 'unsigned int'. Nếu bạn sẵn sàng dựa vào một loại cụ thể thì có 'UINT_MAX', không cần' -' hoặc '~'. Cá nhân tôi sử dụng '-1' trừ khi bit-twiddling. –

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