रिलीज़ मोड में, कोड व्यवहार अपेक्षा के अनुरूप नहीं है


131

निम्न कोड डिबग मोड और रिलीज़ मोड (विज़ुअल स्टूडियो 2008 का उपयोग करके) के तहत विभिन्न परिणाम उत्पन्न करता है:

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;
}

डिबग मोड का आउटपुट, जो अपेक्षित है:

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

रिलीज़ मोड का आउटपुट, जहाँ मैं: 15 परिणाम सही नहीं है:

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

रिलीज़ मोड के तहत विज़ुअल स्टूडियो में "ऑप्टिमाइज़ेशन -> ऑप्टिमाइज़ेशन नहीं" चुनने से, आउटपुट परिणाम सही होगा। हालाँकि मैं जानना चाहूंगा कि ऑप्टिमाइज़ेशन प्रक्रिया गलत आउटपुट क्यों दे सकती है।


अपडेट करें:

जैसा कि मोहित जैनबी ने सुझाव दिया है:

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

रिलीज़ मोड आउटपुट सही है:

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
यह एक कंपाइलर बग की तरह दिखता है (और उस पर काफी महत्वपूर्ण है)।
WhozCraig

1
@HozCraig बस i * 16पोस्ट के आउटपुट को अपडेट करता है , और परिणाम सही है।
लोरिस लिन

4
@juanchopanza: एमएस और बगफिक्स के साथ मेरे अनुभव से लेकर वीएस तक के बारे में सूचित किए जाने के बाद वे ऐसे कीड़े को ठीक करते हैं, लेकिन उन फिक्स को वीएस के पुराने संस्करणों पर लागू नहीं करते हैं, इसलिए यदि किसी कारण से पुराने संस्करण का उपयोग करने के लिए मजबूर किया जाता है वीएस, फिर एक ऐसे कीड़े के साथ फंस जाता है जब तक कि कोई नए संस्करण में अपग्रेड नहीं कर सकता।
कैसरलुडी

2
FWIW यह आगामी विजुअल स्टूडियो 2015 के साथ ठीक काम करता है
ismail

जवाबों:


115

यह दिलचस्प है, कम से कम ऐतिहासिक दृष्टिकोण से। मैं वीसी 2008 (15.00.30729.01) और वीसी 2010 (16.00.40219.01) (32-बिट x86 या 64-बिट x64 को लक्ष्य कर) के साथ समस्या को पुन: उत्पन्न कर सकता हूं । समस्या कुलपतियों 2012 (17.00.61030) के साथ शुरू करने की कोशिश की गई किसी भी संकलक के साथ नहीं होती है।

जिस कमांड का मैं संकलन करता था: cl /Ox vc15-bug.cpp /FAsc

चूंकि VC 2008 (और 2010) पुराना है और अब कई वर्षों के लिए ठीक कर दिया गया है, मुझे नहीं लगता कि आप नए संकलक का उपयोग करने के अलावा Microsoft से किसी भी कार्रवाई की उम्मीद कर सकते हैं (हालांकि शायद कोई वर्कअराउंड का सुझाव दे सकता है)।

समस्या यह है कि यह निर्धारित करने के लिए कि क्या मूल्य के लिए मजबूर किया जाना चाहिए परीक्षण अभिव्यक्ति 255के वास्तविक परिणाम के बजाय लूप काउंट के आधार पर किया जाता है i * 16। और कंपाइलर को केवल उस समय के लिए गलत गणना करना पड़ता है जब उसे मूल्य के लिए मजबूर करना शुरू करना चाहिए 255। मुझे नहीं पता कि ऐसा क्यों होता है - यह सिर्फ इतना प्रभाव है कि मैं देख रहा हूं:

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

  00001 33 f6        xor     esi, esi
$LL4@main:
  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 $LN1@main

; 11   :        {
; 12   :            result = 255;

  0000d b8 ff 00 00 00   mov     eax, 255       ; 000000ffH
$LN1@main:

; 13   :        }

अद्यतन : वीसी के सभी संस्करणों को मैंने वीसी 2008 से पहले स्थापित किया है, जिसमें वीसी 6 को छोड़कर एक ही बग है - कार्यक्रम को संकलित करना वीसीएल कंपाइलर को क्रैश करता है:

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

तो यह एक बग है जो MSVC में एक रूप में या 10 से अधिक वर्षों तक रहता है!


अगर x86 असेंबली टाइमिंग की मेरी मेमोरी सही है तो eax के बजाय esi की तुलना करने का कारण eax है। 255 के कारण पाइपलाइन की स्टाल होगी क्योंकि ex को अभी लिखा गया है।
लोरेन Pechtel

3
मेरा अनुमान (रूपांतरण): परिणाम> २५५, परिणाम / १६> २५५ / १६, मैं> १५, मैं <= १४
तकी

बहुत ही रोचक! इसके अलावा, आप तुलना के परिवर्तित होने से result > 255करने के लिए result >= 255इसे सही ढंग से व्यवहार करता है। VS2010 में परिवर्तन है कि cmp esi, 14करने के लिए cmp esi, 16(और jleकरने के लिए jl)।
opello

16

आपके रिपोर्ट किए गए तथ्यों को सही मानते हुए, यह एक कंपाइलर बग होगा। संकलक के नवीनतम संस्करण की जाँच करें। यदि बग अभी भी मौजूद है, तो बग रिपोर्ट सबमिट करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.