c++ - في وضع الإصدار ، سلوك التعليمات البرمجية ليس كما هو متوقع




optimization visual-studio-2008 (2)

على افتراض أن الحقائق التي أبلغت عنها صحيحة ، فسيكون هذا خطأ في برنامج التحويل البرمجي. تحقق من أحدث إصدار من المحول البرمجي. إذا كان الخطأ لا يزال موجودًا ، فأرسل تقريرًا عن الأخطاء.

تنشئ التعليمة البرمجية التالية نتائج مختلفة ضمن وضع التصحيح ووضع التحرير (باستخدام Visual Studio 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

إخراج وضع الإصدار ، حيث i: 15 نتيجة غير صحيح:

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

باختيار "التحسين -> عدم التحسين" في Visual Studio ضمن وضع الإصدار ، ستكون نتيجة الإخراج صحيحة. ومع ذلك ، أود أن أعرف لماذا يمكن أن تؤدي عملية التحسين إلى إخراج خاطئ.

تحديث:

كما اقترح موهيت جينبي ، يطبع بواسطة:

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

هذا مثير للاهتمام ، على الأقل من منظور تاريخي. يمكنني إعادة إنتاج المشكلة مع VC 2008 (15.00.30729.01) و VC 2010 (16.00.40219.01) (تستهدف إما 32 بت x 86 أو 64 بت x 64 بت). لا تحدث المشكلة مع أي من برامج التحويل البرمجي التي جربتها بدءًا من VC 2012 (17.00.61030).

الأمر الذي اعتدت cl /Ox vc15-bug.cpp /FAsc : 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
[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   :        }

تحديث : جميع إصدارات VC التي قمت بتثبيتها قبل الإصدار 2008 من VC لها نفس الأخطاء ، باستثناء VC6 - تجميع البرنامج يتعطل برنامج التحويل البرمجي VC6:

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

لذلك هذا خطأ استمر في MSVC بشكل أو بآخر لأكثر من 10 سنوات!





compiler-bug