এই লুপটি কেন "সতর্কতা: পুনরাবৃত্তি 3u অপরিজ্ঞাত আচরণের জন্য আহ্বান জানায়" এবং 4 টি লাইনের বেশি আউটপুট দেয়?


162

এটি সংকলন:

#include <iostream>

int main()
{
    for (int i = 0; i < 4; ++i)
        std::cout << i*1000000000 << std::endl;
}

এবং gccনিম্নলিখিত সতর্কতা উত্পাদন করে:

warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
   std::cout << i*1000000000 << std::endl;
                  ^

আমি বুঝতে পারি একটি স্বাক্ষরিত পূর্ণসংখ্যা ওভারফ্লো আছে।

আমি যা পাই না তা হ'ল কেন i ওভারফ্লো অপারেশনের মাধ্যমে মানটি ভেঙে যায়?

আমি উত্তরগুলি পড়েছি কেন জিসিসির সাথে x86 এ পূর্ণসংখ্যার উপচে পড়লে অসীম লুপ হয়? তবে কেন কেন এটি হয় তা সম্পর্কে আমি এখনও পরিষ্কার নই - আমি পেয়েছি যে "অপরিজ্ঞাত" অর্থ "কিছু হতে পারে", তবে এই নির্দিষ্ট আচরণের অন্তর্নিহিত কারণ কি কী?

অনলাইন: http://ideone.com/dMrRKR

কম্পাইলার: gcc (4.8)


49
স্বাক্ষরযুক্ত পূর্ণসংখ্যা ওভারফ্লো => অপরিজ্ঞাত আচরণ => নাসিক ডেমোনস। তবে আমাকে স্বীকার করতে হবে, উদাহরণটি বেশ চমৎকার।
ডায়প

1
সমাবেশের আউটপুট: goo.gl/TtPmZn
ব্রায়ান চেন

1
সঙ্গে জিসিসি 4.8 তারিখে ঘটবে O2, এবং O3পতাকা, কিন্তু না O0বাO1
অ্যালেক্স

3
@dyp আমি যখন নাসিক ডেমোনস পড়ি তখন আমি "ইমগুর হাসি" করলাম যা মজার কিছু দেখলে আপনার নাকটি সামান্য নিঃশ্বাস ত্যাগ করে। এবং তখনই আমি বুঝতে পেরেছিলাম ... আমাকে অবশ্যই একটি নাক ডেমনের দ্বারা অভিশাপ দেওয়া উচিত!
কর্সিকা

4
এই বুকমার্ক তাই আমি পরবর্তী সময় কেউ জবাব লিঙ্ক করতে পারেন "এটা টেকনিক্যালি UB কিন্তু এটা করতে হবে জিনিস " :)
এম এম

উত্তর:


107

স্বাক্ষরিত পূর্ণসংখ্যা ওভারফ্লো (কড়াভাবে বলতে গেলে, "স্বাক্ষরযুক্ত পূর্ণসংখ্যার ওভারফ্লো" বলে কোনও জিনিস নেই) এর অর্থ অনির্ধারিত আচরণ । এবং এর অর্থ যা কিছু ঘটতে পারে, এবং কেন এটি সি ++ এর নিয়মের অধীনে হয় তা নিয়ে আলোচনা করা অর্থহীন নয়।

সি ++ 11 খসড়া এন 3337: §5.4: 1

যদি কোনও অভিব্যক্তির মূল্যায়নের সময়, ফলাফলটি গাণিতিকভাবে ডি-এনড হয় না বা তার ধরণের জন্য উপস্থাপনযোগ্য মানগুলির পরিসরে না হয়, তবে আচরণটি অনুল্কিত হয়। [দ্রষ্টব্য: সি ++ এর সর্বাধিক বিদ্যমান প্রয়োগগুলি fl ow এর চেয়ে বেশি পূর্ণসংখ্যাকে উপেক্ষা করে। শূন্য দ্বারা বিভাজনের চিকিত্সা, শূন্য বিভাজক ব্যবহার করে একটি অবশিষ্ট অংশ গঠন করে এবং সমস্ত ওটিং পয়েন্ট ব্যতিক্রমগুলি মেশিনের মধ্যে পরিবর্তিত হয় এবং সাধারণত একটি লাইব্রেরি ফাংশন দ্বারা নিয়মিত হয়। অন্তর্ভুক্ত নোট]

আপনার কোডটি g++ -O3সতর্কতা সতর্কতার সাথে সংকলিত (এমনকি ছাড়াই -Wall)

a.cpp: In function 'int main()':
a.cpp:11:18: warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
   std::cout << i*1000000000 << std::endl;
                  ^
a.cpp:9:2: note: containing loop
  for (int i = 0; i < 4; ++i)
  ^

প্রোগ্রামটি কী করছে তা বিশ্লেষণের একমাত্র উপায় হ'ল উত্পন্ন সমাবেশ কোডটি পড়া code

এখানে পুরো সমাবেশ তালিকা রয়েছে:

    .file   "a.cpp"
    .section    .text$_ZNKSt5ctypeIcE8do_widenEc,"x"
    .linkonce discard
    .align 2
LCOLDB0:
LHOTB0:
    .align 2
    .p2align 4,,15
    .globl  __ZNKSt5ctypeIcE8do_widenEc
    .def    __ZNKSt5ctypeIcE8do_widenEc;    .scl    2;  .type   32; .endef
__ZNKSt5ctypeIcE8do_widenEc:
LFB860:
    .cfi_startproc
    movzbl  4(%esp), %eax
    ret $4
    .cfi_endproc
LFE860:
LCOLDE0:
LHOTE0:
    .section    .text.unlikely,"x"
LCOLDB1:
    .text
LHOTB1:
    .p2align 4,,15
    .def    ___tcf_0;   .scl    3;  .type   32; .endef
___tcf_0:
LFB1091:
    .cfi_startproc
    movl    $__ZStL8__ioinit, %ecx
    jmp __ZNSt8ios_base4InitD1Ev
    .cfi_endproc
LFE1091:
    .section    .text.unlikely,"x"
LCOLDE1:
    .text
LHOTE1:
    .def    ___main;    .scl    2;  .type   32; .endef
    .section    .text.unlikely,"x"
LCOLDB2:
    .section    .text.startup,"x"
LHOTB2:
    .p2align 4,,15
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB1084:
    .cfi_startproc
    leal    4(%esp), %ecx
    .cfi_def_cfa 1, 0
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    .cfi_escape 0x10,0x5,0x2,0x75,0
    movl    %esp, %ebp
    pushl   %edi
    pushl   %esi
    pushl   %ebx
    pushl   %ecx
    .cfi_escape 0xf,0x3,0x75,0x70,0x6
    .cfi_escape 0x10,0x7,0x2,0x75,0x7c
    .cfi_escape 0x10,0x6,0x2,0x75,0x78
    .cfi_escape 0x10,0x3,0x2,0x75,0x74
    xorl    %edi, %edi
    subl    $24, %esp
    call    ___main
L4:
    movl    %edi, (%esp)
    movl    $__ZSt4cout, %ecx
    call    __ZNSolsEi
    movl    %eax, %esi
    movl    (%eax), %eax
    subl    $4, %esp
    movl    -12(%eax), %eax
    movl    124(%esi,%eax), %ebx
    testl   %ebx, %ebx
    je  L15
    cmpb    $0, 28(%ebx)
    je  L5
    movsbl  39(%ebx), %eax
L6:
    movl    %esi, %ecx
    movl    %eax, (%esp)
    addl    $1000000000, %edi
    call    __ZNSo3putEc
    subl    $4, %esp
    movl    %eax, %ecx
    call    __ZNSo5flushEv
    jmp L4
    .p2align 4,,10
L5:
    movl    %ebx, %ecx
    call    __ZNKSt5ctypeIcE13_M_widen_initEv
    movl    (%ebx), %eax
    movl    24(%eax), %edx
    movl    $10, %eax
    cmpl    $__ZNKSt5ctypeIcE8do_widenEc, %edx
    je  L6
    movl    $10, (%esp)
    movl    %ebx, %ecx
    call    *%edx
    movsbl  %al, %eax
    pushl   %edx
    jmp L6
L15:
    call    __ZSt16__throw_bad_castv
    .cfi_endproc
LFE1084:
    .section    .text.unlikely,"x"
LCOLDE2:
    .section    .text.startup,"x"
LHOTE2:
    .section    .text.unlikely,"x"
LCOLDB3:
    .section    .text.startup,"x"
LHOTB3:
    .p2align 4,,15
    .def    __GLOBAL__sub_I_main;   .scl    3;  .type   32; .endef
__GLOBAL__sub_I_main:
LFB1092:
    .cfi_startproc
    subl    $28, %esp
    .cfi_def_cfa_offset 32
    movl    $__ZStL8__ioinit, %ecx
    call    __ZNSt8ios_base4InitC1Ev
    movl    $___tcf_0, (%esp)
    call    _atexit
    addl    $28, %esp
    .cfi_def_cfa_offset 4
    ret
    .cfi_endproc
LFE1092:
    .section    .text.unlikely,"x"
LCOLDE3:
    .section    .text.startup,"x"
LHOTE3:
    .section    .ctors,"w"
    .align 4
    .long   __GLOBAL__sub_I_main
.lcomm __ZStL8__ioinit,1,1
    .ident  "GCC: (i686-posix-dwarf-rev1, Built by MinGW-W64 project) 4.9.0"
    .def    __ZNSt8ios_base4InitD1Ev;   .scl    2;  .type   32; .endef
    .def    __ZNSolsEi; .scl    2;  .type   32; .endef
    .def    __ZNSo3putEc;   .scl    2;  .type   32; .endef
    .def    __ZNSo5flushEv; .scl    2;  .type   32; .endef
    .def    __ZNKSt5ctypeIcE13_M_widen_initEv;  .scl    2;  .type   32; .endef
    .def    __ZSt16__throw_bad_castv;   .scl    2;  .type   32; .endef
    .def    __ZNSt8ios_base4InitC1Ev;   .scl    2;  .type   32; .endef
    .def    _atexit;    .scl    2;  .type   32; .endef

আমি সবেও অ্যাসেম্বলি পড়তে পারি, তবে আমি addl $1000000000, %ediলাইনটি দেখতে পাচ্ছি । ফলস্বরূপ কোডটি আরও ভাল দেখাচ্ছে

for(int i = 0; /* nothing, that is - infinite loop */; i += 1000000000)
    std::cout << i << std::endl;

@ টিটির এই মন্তব্য:

আমি সন্দেহ করি এটি এর মতো কিছু: (1) কারণ i2 এর চেয়ে বড় যে কোনও মান সহ প্রতিটি পুনরাবৃত্তির আচরণ রয়েছে -> (2) আমরা ধরে নিতে পারি যে i <= 2অপ্টিমাইজেশনের উদ্দেশ্যে -> (3) লুপের অবস্থাটি সর্বদা সত্য -> (4) ) এটি অসীম লুপের মধ্যে অপ্টিমাইজড।

আমাকে কোনও অপরিবর্তিত আচরণ ছাড়াই ওপির কোডের অ্যাসেম্বলি কোডটি নিম্নলিখিত কোডের অ্যাসেম্বলি কোডের সাথে তুলনা করার ধারণা দিয়েছে।

#include <iostream>

int main()
{
    // changed the termination condition
    for (int i = 0; i < 3; ++i)
        std::cout << i*1000000000 << std::endl;
}

এবং, প্রকৃতপক্ষে, সঠিক কোডের সমাপ্তির শর্ত রয়েছে।

    ; ...snip...
L6:
    mov ecx, edi
    mov DWORD PTR [esp], eax
    add esi, 1000000000
    call    __ZNSo3putEc
    sub esp, 4
    mov ecx, eax
    call    __ZNSo5flushEv
    cmp esi, -1294967296 // here it is
    jne L7
    lea esp, [ebp-16]
    xor eax, eax
    pop ecx
    ; ...snip...

ওএমজি, এটি সম্পূর্ণ সুস্পষ্ট নয়! এটা ঠিক না! আমি আগুন দিয়ে বিচার দাবি!

এটির সাথে ডিল করুন, আপনি বগী কোড লিখেছেন এবং আপনার খারাপ লাগা উচিত। পরিণতি বহন করুন।

... বা, বিকল্পভাবে, আরও ভাল ডায়াগনস্টিকস এবং আরও ভাল ডিবাগিং সরঞ্জামগুলির যথাযথ ব্যবহার করুন - এগুলি তাদের জন্য:

  • সমস্ত সতর্কতা সক্ষম করুন

    • -Wallজিসিসি বিকল্পটি কোনও মিথ্যা ধনাত্মকতা ছাড়াই সমস্ত দরকারী সতর্কতাগুলিকে সক্ষম করে। এটি একটি সর্বনিম্ন সর্বনিম্ন যা আপনার সর্বদা ব্যবহার করা উচিত।
    • জিসিসি-তে আরও অনেক সতর্কতা বিকল্প রয়েছে , তবে তারা -Wallমিথ্যা পজিটিভ সম্পর্কে সতর্ক করতে পারে বলে তারা সক্ষম হয় না
    • দুর্ভাগ্যবশত ভিজ্যুয়াল সি ++ দরকারী সতর্কতা দেওয়ার ক্ষমতা নিয়ে পিছিয়ে রয়েছে। কমপক্ষে আইডিই ডিফল্টরূপে কিছু সক্ষম করে।
  • ডিবাগিংয়ের জন্য ডিবাগ পতাকা ব্যবহার করুন

    • পূর্ণসংখ্যার ওভারফ্লো -ftrapvপ্রক্রিয়াকে ওভারফ্লোতে ফাঁদে ফেলে,
    • ঝনঝন সংকলক এর জন্য দুর্দান্ত: -fcatch-undefined-behaviorপ্রচুর সংজ্ঞায়িত আচরণের উদাহরণ ধরে (নোট "a lot of" != "all of them":)

আমার হাতে লেখা কোনও প্রোগ্রামের স্প্যাগেটি জগাখিচুড়ি আছে যা আগামীকালই পাঠানো দরকার! সাহায্য !!!!!! 111oneone

জিসিসি ব্যবহার করুন -fwrapv

এই বিকল্পটি সংকলককে এই অনুমানের নির্দেশ দেয় যে স্বাক্ষরিত গাণিতিক ওভারফ্লোতে যোগ, বিয়োগ এবং গুণটি দ্বিগুণ-পরিপূরক উপস্থাপনা ব্যবহার করে চারপাশে মোড়ানো।

1 - এই নিয়মটি "স্বাক্ষরবিহীন পূর্ণসংখ্যার ওভারফ্লো" এর ক্ষেত্রে প্রযোজ্য নয়, যেমন §3.9.1.4 বলে

স্বাক্ষরযুক্ত স্বাক্ষরযুক্ত স্বাক্ষরবিহীন পূর্ণসংখ্যাগুলি গাণিতিক মডুলো 2 n এর আইন মেনে চলবে যেখানে n নির্দিষ্ট সংখ্যার পূর্ণসংখ্যার মান উপস্থাপনায় বিটের সংখ্যা।

এবং যেমন ফলাফল UINT_MAX + 1গাণিতিকভাবে সংজ্ঞায়িত - গাণিতিক মডুলো 2 এন এর নিয়ম দ্বারা


7
আমি এখনও সত্যিই বুঝতে পারি না যে এখানে কী ঘটছে ... কেন iনিজেই এটি প্রভাবিত হচ্ছে? সাধারণ অপরিবর্তিত আচরণে এই ধরণের অদ্ভুত পার্শ্ব প্রতিক্রিয়া হয় না, সর্বোপরি, i*100000000একটি মূল্যায়ন হওয়া উচিত
vsoftco

26
আমি সন্দেহ করি এটি এর মতো কিছু: (1) কারণ i2 এর চেয়ে বড় যে কোনও মান সহ প্রতিটি পুনরাবৃত্তির আচরণ রয়েছে -> (2) আমরা ধরে নিতে পারি যে i <= 2অপ্টিমাইজেশনের উদ্দেশ্যে -> (3) লুপের অবস্থাটি সর্বদা সত্য -> (4) ) এটি অসীম লুপের মধ্যে অপ্টিমাইজড।
টিসি

28
@ ভসফটকো: যা চলছে তা শক্তি হ্রাসের একটি বিষয় , বিশেষত, ইন্ডাকশন পরিবর্তনশীল নির্মূলকরণ । সংকলক iপ্রেরণকারী কোডের সাহায্যে গুণটিকে সরিয়ে দেয় যা পরিবর্তে প্রতিটি পুনরাবৃত্তিকে 1e9 দ্বারা বৃদ্ধি করে (এবং সেই অনুযায়ী লুপের অবস্থার পরিবর্তন করে)। এটি "যদি" নিয়মের অধীনে এটি একটি যথাযথ বৈধ অপ্টিমাইজেশন যা এই প্রোগ্রামটি পার্থক্যটি পর্যবেক্ষণ করতে পারে না যদি এটি ভাল আচরণ করে। হায়, এটি নেই, এবং অপ্টিমাইজেশন "ফুটো"।
JohannesD

8
@ জোহনেস ডি এই বিরতির কারণটি পেরেক করেছে। তবে লুপ সমাপ্তির শর্ত ওভারফ্লোতে জড়িত না বলে এটি একটি খারাপ অপ্টিমাইজেশন। শক্তি হ্রাসের ব্যবহার ঠিক ছিল - আমি জানি না যে প্রসেসরের গুণকটি (4 * 100000000) এর সাথে কী করবে ((100000000 + 100000000 + 100000000 + 100000000) এর সাথে আলাদা হবে এবং "এটি অপরিজ্ঞাত - কে জানে "যুক্তিসঙ্গত। তবে একটি ভাল আচরণযুক্ত লুপটি কী হওয়া উচিত তা প্রতিস্থাপন, যা 4 বার কার্যকর করে এবং অপরিজ্ঞাত ফলাফল দেয়, এমন কোনও কিছু দিয়ে যা 4 বারের বেশি কার্যকর করে "কারণ এটি অপরিজ্ঞাত!" বোকামি।
জুলি অস্টিন

14
@ জুলিয়িন অস্টিন যদিও এটি আপনার কাছে বোকামি হতে পারে তবে এটি পুরোপুরি আইনী। ইতিবাচক দিক থেকে, সংকলক আপনাকে এটি সম্পর্কে সতর্ক করে।
সহস্রাব্দ

68

সংক্ষিপ্ত উত্তর, gccবিশেষত এই সমস্যাটি নথিভুক্ত করেছে, আমরা দেখতে পাচ্ছি যে জিসিসি ৪.৮ রিলিজ নোটে বলা হয়েছে ( জোর দেওয়া খনি এগিয়ে চলছে ):

ভাষার মান দ্বারা আরোপিত সীমাবদ্ধতাগুলি ব্যবহার করে লুপের পুনরাবৃত্তির সংখ্যার জন্য একটি উপরের গণ্ডি অর্জনের জন্য এখন জিসিসি আরও আক্রমণাত্মক বিশ্লেষণ ব্যবহার করে । এটি অসমাপ্ত প্রোগ্রামগুলিকে প্রত্যাশা অনুযায়ী আর কাজ না করতে পারে যেমন এসপেক সিপিইউ 2006 464.h264ref এবং 416.gamess। এই আক্রমণাত্মক বিশ্লেষণ অক্ষম করতে একটি নতুন বিকল্প, -ফনো-আক্রমণাত্মক-লুপ-অপটিমাইজেশন যুক্ত হয়েছিল। কিছু লুপগুলিতে যা পুনরাবৃত্তির ধ্রুবক সংখ্যা জেনে থাকে, তবে শেষ পুনরাবৃত্তিতে পৌঁছানোর আগে বা অপ্রয়োজনীয় আচরণটি লুপের মধ্যে ঘটে বলে জানা যায়, জিসিসি পুনরাবৃত্তির সংখ্যার নীচের অংশের উপরের অংশটি ব্যতিরেকে লুপের অপরিজ্ঞাত আচরণ সম্পর্কে সতর্ক করবে লুপ জন্য সতর্কতাটি -নো-আক্রমণাত্মক-লুপ-অনুকূলিতকরণের সাথে অক্ষম করা যেতে পারে।

এবং প্রকৃতপক্ষে যদি আমরা ব্যবহার করি -fno-aggressive-loop-optimizations অসীম লুপ ব্যবহার বন্ধ করি এবং এটি আমার পরীক্ষা করা সমস্ত ক্ষেত্রেই ঘটে cases

বুদ্ধিমান যে সঙ্গে দীর্ঘ উত্তর শুরু পূর্ণসংখ্যা স্বাক্ষরিত ওভারফ্লো খসড়া সি ++ মানক বিভাগ দিকে তাকিয়ে অনির্ধারিত আচরণ 5 প্রকাশ অনুচ্ছেদ 4 :

যদি কোনও অভিব্যক্তির মূল্যায়নের সময়, ফলাফলটি গাণিতিকভাবে সংজ্ঞায়িত হয় না বা তার ধরণের জন্য উপস্থাপনযোগ্য মানগুলির পরিসরে থাকে না, তবে আচরণটি নির্ধারিত হয় । [দ্রষ্টব্য: সি ++ এর সর্বাধিক বিদ্যমান প্রয়োগগুলি পূর্ণসংখ্যার ওভারফ্লোগুলিকে উপেক্ষা করে। শূন্য দ্বারা বিভাজনের চিকিত্সা, শূন্য বিভাজক ব্যবহার করে একটি অবশিষ্ট অংশ গঠন করে এবং সমস্ত ভাসমান পয়েন্ট ব্যতিক্রমগুলি মেশিনের মধ্যে পরিবর্তিত হয় এবং সাধারণত একটি লাইব্রেরি ফাংশন দ্বারা নিয়মিত হয়। নোট

আমরা জানি যে স্ট্যান্ডার্ডটি অপরিজ্ঞাত আচরণটি যে নোট থেকে সংজ্ঞা নিয়ে আসে যা বলা হয় যেটি থেকে প্রত্যাশিত:

[দ্রষ্টব্য: এই আন্তর্জাতিক স্ট্যান্ডার্ড আচরণের কোনও সুস্পষ্ট সংজ্ঞা বাদ দিলে বা কোনও প্রোগ্রাম কোনও ভ্রান্ত কাঠামো বা ভুল তথ্য ব্যবহার করে তখন অপরিজ্ঞাত আচরণের আশা করা যেতে পারে। অনুমানযোগ্য অনির্ধারিত আচরণ পরিস্থিতিটি অনির্দেশ্য ফলাফলের সাথে পুরোপুরি উপেক্ষা করা থেকে শুরু করে, পরিবেশের বৈশিষ্ট্যযুক্ত একটি ডকুমেন্টেড পদ্ধতিতে অনুবাদ বা প্রোগ্রামের সম্পাদনার সময় আচরণ করা (ডায়াগনস্টিক বার্তা জারি করা বা ছাড়াই), কোনও অনুবাদ বা কার্যকরকরণ (ইস্যু সহ) ডায়গনিস্টিক বার্তার)। অনেক ভ্রান্ত প্রোগ্রাম নির্মাণগুলি পূর্বনির্ধারিত আচরণকে উত্সাহ দেয় না; সেগুলি নির্ণয়ের প্রয়োজন। অন্তর্ভুক্ত নোট]

তবে বিশ্বের এক্ষেত্রে gccঅপ্টিমাইজার এটিকে অসীম লুপে রূপান্তর করতে কী করতে পারে? এটি সম্পূর্ণ বেহাল মনে হচ্ছে। তবে কৃতজ্ঞতার সাথে gccআমাদের সতর্কবাণীতে এটি বের করার একটি সূত্র দিয়েছে:

warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
   std::cout << i*1000000000 << std::endl;
                  ^

ক্লুটি হ'ল Waggressive-loop-optimizations, তার মানে কী? ভাগ্যক্রমে আমাদের জন্য এই প্রথম এই অপটিমাইজেশনটি কোডটি ভাঙ্গেনি এবং আমরা ভাগ্যবান কারণ জন রেহার জিসিসির প্রাক-৪.৮ নিবন্ধে একটি মামলা নথিভুক্ত করেছেন, ব্রেকড ব্রোকেন এসপিইসি ২০০ Ben বেঞ্চমার্ক যা নিম্নলিখিত কোডটি দেখায়:

int d[16];

int SATD (void)
{
  int satd = 0, dd, k;
  for (dd=d[k=0]; k<16; dd=d[++k]) {
    satd += (dd < 0 ? -dd : dd);
  }
  return satd;
}

নিবন্ধটি বলে:

অপরিবর্তিত আচরণ লুপ থেকে বেরিয়ে আসার ঠিক পূর্বে d [16] এ অ্যাক্সেস করছে। C99 এ অ্যারের শেষের আগে একটি অবস্থানে কোনও পয়েন্টার তৈরি করা আইনসম্মত, তবে সেই পয়েন্টারটিকে অবশ্যই অবচয় করা উচিত নয়।

এবং পরে বলেছেন:

বিস্তারিত, এখানে যা চলছে তা এখানে। এসি সংকলক, ডি [++ কে] দেখার পরে, ধরে নেওয়া যায় যে কে এর বর্ধিত মান অ্যারের সীমানার মধ্যে রয়েছে, অন্যথায় অপরিবর্তিত আচরণ দেখা দেয়। কোডটির জন্য , জিসিসি অনুমান করতে পারে যে কে 0,1 এর মধ্যে রয়েছে। কিছুক্ষণ পরে, যখন জিসিসি কে <16 দেখেন, তখন এটি নিজের কাছে বলে: "আহা – অভিব্যক্তিটি সর্বদা সত্য, সুতরাং আমাদের একটি অসীম লুপ রয়েছে” " এখানে পরিস্থিতি, যেখানে সংকলক একটি দরকারী ডেটাফ্লো তথ্য নির্ধারণের জন্য সু-সংজ্ঞায়নের অনুমান ব্যবহার করে,

তাই কিছু ক্ষেত্রে কম্পাইলার অবশ্যই যা করছেন তা ধরে নেওয়া হচ্ছে যেহেতু স্বাক্ষরকৃত পূর্ণসংখ্যার ওভারফ্লো অনির্ধারিত আচরণ তাই iসর্বদা এর চেয়ে কম হওয়া উচিত4 এবং এইভাবে আমাদের একটি অসীম লুপ রয়েছে।

তিনি ব্যাখ্যা করেছেন এটি কুখ্যাত লিনাক্স কার্নেল নাল পয়েন্টার চেক অপসারণের সাথে খুব মিল, যেখানে এই কোডটি দেখেছেন:

struct foo *s = ...;
int x = s->f;
if (!s) return ERROR;

gccঅনুমান করা হয়েছে যেহেতু একটি নাল পয়েন্টারকে sঅবজ্ঞাপিত করা হয়েছে s->f;তাই অপরিজ্ঞাত আচরণ sতাই নালাগুলি হওয়া উচিত নয় এবং তাই if (!s)পরবর্তী লাইনে থাকা চেকটি অপ্টিমাইজ করে ।

এখানে পাঠটি হ'ল আধুনিক অপ্টিমাইজারগুলি অনির্ধারিত আচরণের শোষণ সম্পর্কে খুব আক্রমণাত্মক এবং সম্ভবত সম্ভবত আরও আক্রমণাত্মক হবে। পরিষ্কারভাবে মাত্র কয়েকটি উদাহরণ সহ আমরা দেখতে পাচ্ছি যে অপ্টিমাইজার এমন কিছু কাজ করে যা কোনও প্রোগ্রামারকে সম্পূর্ণ অযৌক্তিক বলে মনে হয় তবে অপ্টিমাইজারের দৃষ্টিভঙ্গি থেকে পিছনে ফিরে আসে।


7
আমি বুঝতে পারি যে সংকলক লেখক এটিই করছেন (আমি সংকলকগুলি লিখতে এবং এমনকি একটি অপ্টিমাইজার বা দুটিও ব্যবহার করতাম), তবে এমন আচরণগুলি রয়েছে যেগুলি "অপরিজ্ঞাত" হলেও "দরকারী" এবং এই পদযাত্রা আরও বেশি আক্রমণাত্মক অপ্টিমাইজেশনের দিকে কেবল উন্মাদনা। উপরে আপনি যে উদ্ধৃতিটি উদ্ধৃত করেছেন তা ভুল, তবে ত্রুটি চেকটিকে অপ্টিমাইজ করা ব্যবহারকারী-প্রতিকূল।
জুলি অস্টিন

1
@ জুলিয়িন অস্টিন আমি সম্মতি জানাই এটি একটি আশ্চর্যজনক আচরণ, বলছি যে বিকাশকারীদের অপরিজ্ঞাত আচরণ এড়ানো দরকার সত্যিকার অর্ধেক বিষয়। স্পষ্টতই সংকলকটির বিকাশকারীকে আরও ভাল প্রতিক্রিয়া সরবরাহ করতে হবে। এক্ষেত্রে একটি সতর্কতা উত্পন্ন করা হয় যদিও এটি সত্যই যথেষ্ট তথ্যবহুল নয়।
শফিক ইয়াঘমোর

3
আমি মনে করি এটি একটি ভাল জিনিস, আমি আরও ভাল, দ্রুত কোড চাই। ইউবি কখনই ব্যবহার করা উচিত নয়।
পলম

1
@ পলম নৈতিকভাবে ইউবি স্পষ্টতই খারাপ তবে উন্নততর অ্যাপ্লিকেশনগুলিকে প্রভাবিত করার আগে বিকাশকারীদের ইউবি এবং অন্যান্য সমস্যাগুলি ধরতে সহায়তা করার জন্য ক্ল্যাং স্ট্যাটিক অ্যানালাইজারের মতো আরও ভাল সরঞ্জাম সরবরাহ করার পক্ষে তর্ক করা শক্ত ।
শফিক ইয়াঘমোর

1
@ শফিকিক ইয়াঘমুর এছাড়াও, আপনার বিকাশকারী যদি সতর্কতাগুলি উপেক্ষা করে থাকেন, তবে তারা ঝাঁকুনির আউটপুটটিতে কীভাবে মনোযোগ দেবেন এমন সম্ভাবনা কত? এই সমস্যাটি সহজেই আক্রমণাত্মক "বিনা বিচারে সতর্কতা" নীতি দ্বারা ধরা পড়তে পারে। ঝনঝন পরামর্শ দেওয়া কিন্তু প্রয়োজন হয় না।
ডিফোর্ড

24

tl; dr কোডটি একটি পরীক্ষা তৈরি করে যা পূর্ণসংখ্যার + ধনাত্মক পূর্ণসংখ্য == negativeণাত্মক পূর্ণসংখ্যা । সাধারণত অপ্টিমাইজার এটিকে অনুকূল করে না, তবে std::endlপরবর্তীটি ব্যবহৃত হওয়ার নির্দিষ্ট ক্ষেত্রে, সংকলকটি এই পরীক্ষারটিকে সর্বোত্তম করে তোলে। আমি endlএখনও বিশেষ কিছু খুঁজে বের করতে পারেনি।


-O1 এবং উচ্চতর স্তরের সমাবেশ কোড থেকে, এটি পরিষ্কার যে জিসিসি লুপটি রিফ্যাক্টরগুলিতে:

i = 0;
do {
    cout << i << endl;
    i += NUMBER;
} 
while (i != NUMBER * 4)

সবচেয়ে ভাল মান যা সঠিকভাবে কাজ করে তা হ'ল 715827882তল ( INT_MAX/3)। এসেম্বলির স্নিপেটটি -O1হ'ল:

L4:
movsbl  %al, %eax
movl    %eax, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSo3putEc
movl    %eax, (%esp)
call    __ZNSo5flushEv
addl    $715827882, %esi
cmpl    $-1431655768, %esi
jne L6
    // fallthrough to "return" code

মনে রাখবেন, -1431655768হয় 4 * 715827882সম্পূরক 2 এর হবে।

হিট হ'ল -O2এটি নিম্নলিখিতটিকে অনুকূল করে:

L4:
movsbl  %al, %eax
addl    $715827882, %esi
movl    %eax, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSo3putEc
movl    %eax, (%esp)
call    __ZNSo5flushEv
cmpl    $-1431655768, %esi
jne L6
leal    -8(%ebp), %esp
jne L6 
   // fallthrough to "return" code

সুতরাং যে অপটিমাইজেশনটি করা হয়েছে তা কেবলমাত্র addlউচ্চতর স্থানান্তরিত হয়েছিল।

715827883পরিবর্তে আমরা যদি পুনরায় কম্পাইল করি তবে পরিবর্তিত নম্বর এবং পরীক্ষার মান বাদে -O1 সংস্করণটি অভিন্ন। তবে -O2 এর পরে একটি পরিবর্তন হয়:

L4:
movsbl  %al, %eax
addl    $715827883, %esi
movl    %eax, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSo3putEc
movl    %eax, (%esp)
call    __ZNSo5flushEv
jmp L2

কোথায় ছিল cmpl $-1431655764, %esi-O1, যে লাইন জন্য সরানো হয়েছে -O2। অপ্টিমাইজার অবশ্যই সিদ্ধান্ত নিয়েছে যে যোগ 715827883করা %esiকখনই সমান হতে পারে না-1431655764

এটা বেশ চমকপ্রদ। যোগ করা হচ্ছে যে INT_MIN+1 করে , প্রত্যাশিত ফলাফলের উৎপন্ন তাই অপটিমাইজার সিদ্ধান্ত নিয়েছি হবে যে %esiহতে পারে নাINT_MIN+1 এবং আমি নিশ্চিত কেন এটা যে সিদ্ধান্ত নিতে হবে নই।

কাজের উদাহরণে মনে হয় এটি একটি সমান বৈধ হতে হবে যে এই সিদ্ধান্তে পৌঁছাতে যে 715827882কোনও সংখ্যায় যোগ করা সমান হতে পারে না INT_MIN + 715827882 - 2! (এটি কেবল তখনই সম্ভব যদি র্যাপআরাউন্ডটি প্রকৃতপক্ষে ঘটে) তবে এটি উদাহরণটিতে লাইনটি অনুকূলিত করে না।


আমি যে কোডটি ব্যবহার করছিলাম তা হ'ল:

#include <iostream>
#include <cstdio>

int main()
{
    for (int i = 0; i < 4; ++i)
    {
        //volatile int j = i*715827883;
        volatile int j = i*715827882;
        printf("%d\n", j);

        std::endl(std::cout);
    }
}

যদি std::endl(std::cout)অপসারণ করা হয় তবে অপ্টিমাইজেশন আর ঘটে না। প্রকৃতপক্ষে এটি প্রতিস্থাপনের সাথে ইনলাইন std::cout.put('\n'); std::flush(std::cout);হওয়া সত্ত্বেও অপ্টিমাইজেশনটি ঘটবে না std::endl

অন্তর্নিহিতকরণটি std::endlলুপ কাঠামোর আগের অংশটিকে প্রভাবিত করবে বলে মনে হচ্ছে (এটি আমি কী করে তা বেশিরভাগই বুঝতে পারি না তবে অন্য কারও ক্ষেত্রে আমি এখানে এটি পোস্ট করব):

মূল কোড সহ এবং -O2:

L2:
movl    %esi, 28(%esp)
movl    28(%esp), %eax
movl    $LC0, (%esp)
movl    %eax, 4(%esp)
call    _printf
movl    __ZSt4cout, %eax
movl    -12(%eax), %eax
movl    __ZSt4cout+124(%eax), %ebx
testl   %ebx, %ebx
je  L10
cmpb    $0, 28(%ebx)
je  L3
movzbl  39(%ebx), %eax
L4:
movsbl  %al, %eax
addl    $715827883, %esi
movl    %eax, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSo3putEc
movl    %eax, (%esp)
call    __ZNSo5flushEv
jmp L2                  // no test

এর mymanual ইনলাইনিং সঙ্গে std::endl, -O2:

L3:
movl    %ebx, 28(%esp)
movl    28(%esp), %eax
addl    $715827883, %ebx
movl    $LC0, (%esp)
movl    %eax, 4(%esp)
call    _printf
movl    $10, 4(%esp)
movl    $__ZSt4cout, (%esp)
call    __ZNSo3putEc
movl    $__ZSt4cout, (%esp)
call    __ZNSo5flushEv
cmpl    $-1431655764, %ebx
jne L3
xorl    %eax, %eax

এই দুটিয়ের মধ্যে একটি পার্থক্য হ'ল %esiমূল এবং %ebxদ্বিতীয় সংস্করণে ব্যবহৃত হয়; শব্দার্থবিজ্ঞানের মধ্যে %esiএবং %ebxসাধারণের মধ্যে কোনও পার্থক্য রয়েছে কি? (আমি x86 সমাবেশ সম্পর্কে খুব বেশি জানি না)।


অপ্টিমাইজারের যুক্তিটি ঠিক কী ছিল তা সন্ধান করা ভাল হ'ল, এই পর্যায়ে আমার কাছে স্পষ্ট হয় না যে কিছু ক্ষেত্রে কেন পরীক্ষাটি অপ্টিমাইজ করা হয়েছে এবং কিছু কিছু নেই
এমএম

8

জিসিসি-তে এই ত্রুটিটির প্রতিবেদন করার আরেকটি উদাহরণ হ'ল যখন আপনার কাছে এমন একটি লুপ থাকে যা ধ্রুব সংখ্যক পুনরাবৃত্তির জন্য কার্যকর করে তবে আপনি পাল্টা ভেরিয়েবলটিকে একটি অ্যারেতে সূচক হিসাবে ব্যবহার করছেন যা এর চেয়ে কম আইটেমের চেয়ে কম রয়েছে:

int a[50], x;

for( i=0; i < 1000; i++) x = a[i];

সংকলক নির্ধারণ করতে পারে যে এই লুপটি অ্যারে 'এ' এর বাইরে মেমরি অ্যাক্সেস করার চেষ্টা করবে। সংকলক এই বরং ক্রিপ্টিক বার্তা দিয়ে এই সম্পর্কে অভিযোগ:

পুনরাবৃত্তি xxu অপরিবর্তিত আচরণের জন্য আহ্বান জানায় [-Werror = আগ্রাসী-লুপ-অনুকূলিতকরণ]


আরও ক্রিপ্টিকটি হ'ল বার্তাটি কেবল তখনই অপটিমাইজেশন চালু হয়। এম $ ভিবি বার্তা "আউট আউট আউট অফ ডামি"?
রবি গণেশ

6

আমি যা পাই না তা হ'ল কেন ওভারফ্লো অপারেশনের মাধ্যমে আমি মূল্য ভেঙেছি?

দেখে মনে হচ্ছে যে চতুর্থ পুনরাবৃত্তিতে (এর জন্য i = 3) পূর্ণসংখ্যার ওভারফ্লো ঘটে । signedপূর্ণসংখ্যা ওভারফ্লো অনির্ধারিত আচরণের জন্য প্রার্থনা করে । এক্ষেত্রে কিছুই অনুমান করা যায় না। লুপটি কেবল বারবার পুনরাবৃত্তি হতে পারে 4বা এটি অসীম বা অন্য কোনও কিছুতে যেতে পারে!
সংকলক থেকে এমনকি একই সংকলকের বিভিন্ন সংস্করণের জন্যও ফলাফলটি পৃথক হতে পারে।

সি 11: 1.3.24 অপরিবর্তিত আচরণ:

এই আন্তর্জাতিক স্ট্যান্ডার্ডটি কোনও প্রয়োজনের জন্য
চাপায় না এমন আচরণ [দ্রষ্টব্য: এই আন্তর্জাতিক স্ট্যান্ডার্ড আচরণের কোনও স্পষ্ট সংজ্ঞা বাদ দিলে বা যখন কোনও প্রোগ্রাম একটি ভ্রান্ত নির্মাণ বা ভুল ডেটা ব্যবহার করে তখন অপরিজ্ঞাত আচরণের আশা করা যেতে পারে। অনুমানযোগ্য অনির্ধারিত আচরণ পরিস্থিতিটি অনির্দেশ্য ফলাফলের সাথে পুরোপুরি উপেক্ষা করা থেকে শুরু করে, পরিবেশের বৈশিষ্ট্যযুক্ত একটি ডকুমেন্টেড পদ্ধতিতে অনুবাদ বা প্রোগ্রামের সম্পাদনার সময় আচরণ করা (ডায়াগনস্টিক বার্তা জারি করা বা ছাড়াই), কোনও অনুবাদ বা কার্যকরকরণ (ইস্যু সহ) ডায়গনিস্টিক বার্তার) । অনেক ভ্রান্ত প্রোগ্রাম নির্মাণগুলি পূর্বনির্ধারিত আচরণকে উত্সাহ দেয় না; সেগুলি নির্ণয়ের প্রয়োজন। অন্তর্ভুক্ত নোট]


@bits_international; হ্যাঁ.
হ্যাকগুলি

4
আপনি ঠিক বলেছেন, কেন আমি নিম্নচাপেছিলাম তা ব্যাখ্যা করার পক্ষে এটি ন্যায়সঙ্গত। এই উত্তরের তথ্যটি সঠিক, তবে এটি শিক্ষামূলক নয় এবং এটি রুমে থাকা হাতিটিকে পুরোপুরি উপেক্ষা করে: অবিচ্ছিন্নতা অপ্রত্যাশনের কারণে পরিচালিত অপারেশনের চেয়ে পৃথক স্থানে (থামার শর্তে) স্পষ্টতই ঘটে । এই নির্দিষ্ট ক্ষেত্রে জিনিসগুলি কীভাবে ভাঙা যায় তার যান্ত্রিকতা ব্যাখ্যা করা হয়নি, যদিও এটি এই প্রশ্নের মূল বিষয়। এটি একটি সাধারণ খারাপ শিক্ষকের পরিস্থিতি যেখানে শিক্ষকের উত্তর কেবল সমস্যার মূল বিষয়টিকেই চিহ্নিত করে না, এটি আরও প্রশ্নকে নিরুৎসাহিত করে। এটি প্রায় মনে হচ্ছে ...
স্যাজাবলস

5
"আমি দেখছি এটি অনির্ধারিত আচরণ, এবং এদিক থেকে আমি কীভাবে বা কেন এটি ভেঙে যায় তা বিবেচনা করি না The মানকটি এটি ভাঙতে দেয় further আর কোনও প্রশ্ন নেই" " আপনি এটি এর মতো বোঝাতে পারেন নি তবে এটি মনে হচ্ছে। আমি এসও-তে এর (দুর্ভাগ্যজনকভাবে প্রচলিত) দৃষ্টিভঙ্গির কম দেখার আশা করছি। এটি ব্যবহারিকভাবে কার্যকর নয়। আপনি যদি ব্যবহারকারী ইনপুট পান তবে প্রতিটি একক স্বাক্ষরিত পূর্ণসংখ্যার ক্রিয়াকলাপের পরে ওভারফ্লো পরীক্ষা করা যুক্তিসঙ্গত নয় , এমনকি যদি স্ট্যান্ডার্ডটি বলে যে প্রোগ্রামটির অন্য কোনও অংশ এটির কারণে প্রস্ফুটিত হতে পারে। কীভাবে এটি ভেঙে যায় তা বোঝা অনুশীলনে এই জাতীয় সমস্যা এড়াতে সহায়তা করে
সজ্জাবলস

2
@ সাজাবল্যাক্স: সিটিকে দুটি ভাষা হিসাবে বিবেচনা করা ভাল, যার মধ্যে একটি সহজ সংকলককে নির্মাণকারীদের সাহায্যে যুক্তিযুক্ত-কার্যকর এক্সিকিউটেবল কোড অর্জনের অনুমতি দেওয়ার জন্য ডিজাইন করা হয়েছিল যারা নির্ধারিত টার্গেট প্ল্যাটফর্মগুলিতে নির্ভরযোগ্য তবে এটি নয় অন্যরা, এবং ফলস্বরূপ স্ট্যান্ডার্ড কমিটি দ্বারা উপেক্ষা করা হয়েছিল, এবং একটি দ্বিতীয় ভাষা যা এই ধরণের সমস্ত নির্মাণকে বাদ দেয় যার জন্য স্ট্যান্ডার্ড সমর্থন জারি করে না, কম্পাইলারদের অতিরিক্ত অপ্টিমাইজেশন প্রয়োগ করার অনুমতি দেয় যা প্রোগ্রামারদের হতে পারে বা তার চেয়ে বেশি হতে পারে ছেড়ে দেত্তয়া.
সুপারক্যাট

1
@ স্যাজাবলাকস " আপনি যদি ব্যবহারকারী ইনপুট পান তবে প্রতিটি স্বাক্ষরিত পূর্ণসংখ্যার ক্রিয়াকলাপের পরে ওভারফ্লো পরীক্ষা করা যুক্তিসঙ্গত নয় " - সঠিক কারণ এই মুহুর্তে এটি অনেক দেরিতে। প্রতিটি একক স্বাক্ষরিত পূর্ণসংখ্যা ক্রিয়াকলাপের আগে আপনাকে ওভারফ্লো পরীক্ষা করতে হবে ।
মেলপোমেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.