2015-07-09 24 views
130

Đoạn mã dưới đây tạo ra kết quả khác nhau dưới chế độ debug và chế độ phát hành (sử dụng Visual Studio 2008):Trong chế độ phát hành, hành vi mã không như mong đợi

int _tmain(int argc, _TCHAR* argv[]) 
{ 

    for(int i = 0; i < 17; i++) 
    { 
     int result = i * 16; 

     if(result > 255) 
     { 
      result = 255; 
     } 

     printf("i:%2d, result = %3d\n", i, result) ; 
    } 

    return 0; 
} 

Kết quả của chế độ debug, được như mong đợi :

i: 0, result = 0 
i: 1, result = 16 
(...) 
i:14, result = 224 
i:15, result = 240 
i:16, result = 255 

kết quả của chế độ phát hành, trong đó i: 15 kết quả là không đúng:

i: 0, result = 0 
i: 1, result = 16 
(...) 
i:14, result = 224 
i:15, result = 255 
i:16, result = 255 

Bằng cách chọn "Tối ưu hóa -> Không tối ưu hóa" trong Visual Studio trong chế độ phát hành, kết quả đầu ra sẽ chính xác. Tuy nhiên tôi muốn biết lý do tại sao quá trình tối ưu hóa có thể dẫn đến đầu ra sai.


Cập nhật:

Theo đề nghị của Mohit JainBy, in theo:

printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ; 

Các chế độ phát hành ra là đúng:

i: 0, result = 0, i*16=0 
i: 1, result = 16, i*16=16 
(...) 
i:14, result = 224, i*16=224 
i:15, result = 240, i*16=240 
i:16, result = 255, i*16=256 
+15

Trông giống như lỗi trình biên dịch (và một lỗi khá quan trọng ở đó). – WhozCraig

+1

@WhozCraig Chỉ cập nhật đầu ra của 'i * 16' trong bài đăng và kết quả là chính xác. –

+4

@juanchopanza: Từ kinh nghiệm của tôi với MS và sửa lỗi cho VS họ sửa lỗi như vậy sau khi họ được thông báo về họ, nhưng không áp dụng các bản sửa lỗi cho phiên bản cũ hơn của VS, vì vậy nếu một lý do buộc phải sử dụng Phiên bản của VS, sau đó một là bị mắc kẹt với các lỗi như vậy cho đến khi người ta có thể nâng cấp lên một phiên bản mới hơn. – Kaiserludi

Trả lời

114

Điều này thật thú vị, ít nhất là từ góc độ lịch sử. Tôi có thể tái tạo sự cố với VC 2008 (15.00.30729.01) VC 2010 (16.00.40219.01) (nhắm mục tiêu 32 bit x86 hoặc 64-bit x64). Vấn đề không xảy ra với bất kỳ trình biên dịch nào mà tôi đã thử bắt đầu với VC 2012 (17.00.61030).

Lệnh tôi sử dụng để biên dịch: cl /Ox vc15-bug.cpp /FAsc

Kể từ khi VC 2008 (và 2010) là khá cũ và sửa chữa đã được trong nhiều năm nay, tôi không nghĩ rằng bạn có thể mong đợi bất kỳ hành động từ Microsoft trừ để sử dụng trình biên dịch mới hơn (mặc dù có thể ai đó có thể đề xuất giải pháp thay thế).

Vấn đề là kiểm tra để xác định xem giá trị có bị buộc phải 255 được thực hiện dựa trên số vòng lặp thay vì kết quả thực tế của biểu thức i * 16 hay không. Và trình biên dịch chỉ đơn giản là đếm số sai khi nó bắt đầu buộc giá trị là 255. Tôi không có ý tưởng tại sao điều đó xảy ra - nó chỉ là hiệu quả mà tôi thấy:

; 6 : for(int i = 0; i < 17; i++) 

    00001 33 f6  xor  esi, esi 
[email protected]: 
    00003 8b c6  mov  eax, esi 
    00005 c1 e0 04  shl  eax, 4 

; 7 : { 
; 8 :  int result = i * 16; 
; 9 : 
; 10 :  if(result > 255) 

    // the value `esi` is compared with in the following line should be 15! 
    00008 83 fe 0e  cmp  esi, 14   ; 0000000eH 
    0000b 7e 05  jle  SHORT [email protected] 

; 11 :  { 
; 12 :   result = 255; 

    0000d b8 ff 00 00 00 mov  eax, 255  ; 000000ffH 
[email protected]: 

; 13 :  } 

Cập nhật: Tất cả các phiên bản của VC Tôi đã cài đặt sớm hơn VC 2008 có lỗi tương tự, ngoại trừ VC6 - biên soạn chương trình bị treo trình biên dịch VC6:

vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR 

Vì vậy, đây là lỗi kéo dài trong MSVC dưới dạng này hay dạng khác trong hơn 10 năm!

+0

Nếu bộ nhớ của tôi về thời gian lắp ráp x86 là đúng lý do để so sánh với ESI thay vì eax là ea eax, 255 sẽ gây ra một gian hàng đường ống như eax vừa được viết. –

+3

Tôi đoán (biến đổi): kết quả> 255, kết quả/16> 255/16, i> 15, i <= 14 – teki

+0

Rất thú vị! Ngoài ra nếu bạn thay đổi so sánh từ 'kết quả> 255' thành' kết quả> = 255' thì nó hoạt động chính xác. Trong VS2010 thay đổi 'cmp esi, 14' thành' cmp esi, 16' (và 'jle' thành' jl'). – opello

16

Giả sử sự kiện báo cáo của bạn đúng, đây sẽ là lỗi trình biên dịch. Kiểm tra phiên bản mới nhất của trình biên dịch. Nếu vẫn còn lỗi, hãy gửi báo cáo lỗi.

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