এটি একটি কলঙ্ক বাগ
... যখন অসীম লুপযুক্ত ফাংশনটি ইনলাইন করা হয়। while(1);
সরাসরি প্রদর্শিত হয় যখন আচরণটি পৃথক , যা আমার খুব গন্ধযুক্ত গন্ধ।
দেখা একটি সংক্ষিপ্তসার এবং লিঙ্কগুলির জন্য @ আরনভিওনের উত্তর । এই উত্তরটির বাকী অংশটি আমার নিশ্চিত হওয়ার আগেই লেখা হয়েছিল যে এটি একটি বাগ ছিল, একটি পরিচিত বাগটি ছেড়ে দেওয়া যাক।
শিরোনাম প্রশ্নের উত্তর দেওয়ার জন্য: আমি কীভাবে এমন একটি অসীম ফাঁকা লুপ তৈরি করব যা অপ্টিমাইজ হবে না? ? -
করা die()
একটি ম্যাক্রো, না একটি ফাংশন এই বাগটি ক্ল্যাং ৩.৯ এবং এর পরে কাজ করার জন্য । (পূর্ববর্তী ঝনঝন সংস্করণগুলি হয় লুপটি রাখে বাcall
অসীম লুপের সাথে ফাংশনের একটি অন-ইনলাইন সংস্করণে print;while(1);print;
প্রেরণ করে )) ফাংশনটি তার কলারের সাথে ইনলাইন করে নিলে এটি নিরাপদ বলে মনে হয় ( গডবোল্ট) )) ) সাথে । -std=gnu11
বনাম -std=gnu99
কিছু পরিবর্তন করে না।
যদি আপনি কেবল জিএনইউ সি সম্পর্কে চিন্তা করেন তবে লুপের ভিতরে পি__জে__ এর__asm__("");
কাজও কাজ করে এবং এটি বোঝে এমন কোনও সংকলকগুলির জন্য আশেপাশের কোনও কোডের অপ্টিমাইজেশনের ক্ষতি করা উচিত নয়। জিএনইউ সি বেসিক asm স্টেটমেন্টগুলি পরোক্ষভাবেvolatile
, তাই একটি দৃশ্যমান পার্শ্ব প্রতিক্রিয়া যেমন সি বিমূর্ত মেশিনে would অনেকবার হিসাবে "চালানো" আছে যা এই গন্য। (এবং হ্যাঁ, ক্ল্যাং জিসিসি ম্যানুয়াল দ্বারা নথিভুক্ত হিসাবে সি এর জিএনইউ উপভাষা প্রয়োগ করে))
কিছু লোক যুক্তি দেখিয়েছেন যে খালি অসীম লুপটি অপ্টিমাইজ করা আইনী হতে পারে। আমি 1 রাজি নই , তবে আমরা তা মেনে নিলেও তা পারছে না এছাড়াও আইনি ঝনঝন অনুমান জন্য লুপ পর বিবৃতি অনধিগম্য হয়, হতে এবং পরবর্তী ফাংশন মধ্যে ফাংশন শেষে বন্ধ সঞ্চালনের পড়া যাক, অথবা আবর্জনা মধ্যে এলোমেলো নির্দেশ হিসাবে ডিকোড।
(এটি ক্ল্যাং ++ এর জন্য মান-সম্মতিযুক্ত হবে (তবে এখনও খুব কার্যকর নয়); কোনও পার্শ্ব প্রতিক্রিয়া ছাড়াই অসীম লুপগুলি সি ++ তে ইউবি হয়, তবে সি নয় C.
হয় ( ) যখন রয়েছে; ইউবি সংকলকটি মূলত নির্গত করতে দেয় মৃত্যুদন্ড কার্যকর করার পথে কোডের জন্য যা অবশ্যই ইউবির মুখোমুখি হবে asm
the লুপের একটি বিবৃতি সি ++ এর জন্য এই ইউবিটিকে এড়িয়ে চলবে But তবে অনুশীলন হিসাবে, সি ++ হিসাবে ক্ল্যাং সংকলন ধ্রুবক-এক্সপ্রেশন অসীম খালি লুপগুলি সরিয়ে রাখবে না যখন ইনলাইনিংয়ের সময়, একইভাবে সি হিসাবে সংকলন)
ম্যানুয়ালি ইনলাইনিং while(1);
পরিবর্তন করে যে কীভাবে ক্ল্যাং এটি সংকলন করে: অসমের মধ্যে অসীম লুপ উপস্থিত। আমরা কোনও নিয়ম-আইনজীবী পিওভের কাছ থেকে এটি প্রত্যাশা করব।
#include <stdio.h>
int main() {
printf("begin\n");
while(1);
//infloop_nonconst(1);
//infloop();
printf("unreachable\n");
}
গডবোল্ট সংকলক এক্সপ্লোরারটিতে , -xc
x86-64 এর জন্য সি ( ) হিসাবে সংকলন 9.0 -O3 ক্ল্যাং :
main: # @main
push rax # re-align the stack by 16
mov edi, offset .Lstr # non-PIE executable can use 32-bit absolute addresses
call puts
.LBB3_1: # =>This Inner Loop Header: Depth=1
jmp .LBB3_1 # infinite loop
.section .rodata
...
.Lstr:
.asciz "begin"
একই বিকল্পগুলির সাথে একই সংকলক একটি সংকলন করে main
যা infloop() { while(1); }
প্রথমে একই সাথে কল করে puts
, কিন্তু তারপরে কেবল main
সেই বিন্দুর পরে নির্গমন নির্দেশগুলি থামিয়ে দেয় । সুতরাং আমি যেমন বলেছি, মৃত্যুদন্ড কার্যকর হ'ল ফাংশনটির সমাপ্তি, পরবর্তী যে কোনও ফাংশনে (তবে ফাংশন এন্ট্রির জন্য স্ট্যাকের সাথে ভুল চিহ্নযুক্ত যাতে এটি কোনও বৈধ টেলকলও নয়)।
বৈধ বিকল্পগুলি হবে
label: jmp label
অসীম লুপ নির্গত করুন
- বা (যদি আমরা স্বীকার করি যে অসীম লুপটি সরানো যেতে পারে) ২ য় স্ট্রিং মুদ্রণের জন্য অন্য কলটি প্রেরণ করে এবং এর
return 0
থেকে main
।
"অ্যাক্সেসযোগ্য" মুদ্রণ না করে ক্রাশ করা বা অন্যথায় চালিয়ে যাওয়া কোনও সি 11 বাস্তবায়নের জন্য স্পষ্টতই ঠিক নয়, যদি না ইউবি থাকে যা আমি লক্ষ্য করি না।
পাদটীকা 1:
রেকর্ডের জন্য, আমি @ লন্ডিনের উত্তরটির সাথে সম্মত যা মানকে উদ্ধৃত করে প্রমাণের জন্য যে সি 11 খালি থাকার পরেও ধ্রুবক-এক্সপ্রেশন অসীম লুপগুলিকে সমাপ্তির অনুমানের অনুমতি দেয় না (আই / ও, অস্থির, সিঙ্ক্রোনাইজেশন বা অন্য কোনও নয়) দৃশ্যমান পার্শ্ব প্রতিক্রিয়া)।
এটি অবস্থার সেট যা একটি লুপকে ফাঁকা asm লুপে সংকলন করতে দেয় একটি সাধারণ সিপিইউর জন্য একটি । (উত্সটিতে দেহটি খালি না থাকলেও লুপটি চলাকালীন ভেরিয়েবলের অ্যাসাইনমেন্টগুলি থ্রেড বা রেসালীন ইউবি ব্যতীত অন্য থ্রেড বা সিগন্যাল হ্যান্ডলারের কাছে দৃশ্যমান হতে পারে না So সুতরাং একটি অনুসারী বাস্তবায়ন যদি এটি চায় তবে এই জাতীয় লুপগুলি মুছে ফেলতে পারে টু। তারপরে লুপটি নিজেই মুছে ফেলা যায় কিনা এই প্রশ্নটি ছেড়ে দেয় ISO আইএসও সি 11 স্পষ্টভাবে না বলে)
C11 সিলেসিসের ক্ষেত্রে কেসটিকে একত্রিত করে যেখানে বাস্তবায়ন লুপটি সমাপ্ত হতে পারে না (এবং এটি ইউবি নয়), এটি স্পষ্ট বলে মনে হয় যে তারা লুপটি রান-টাইমে উপস্থিত থাকার ইচ্ছে করে। এমন একটি বাস্তবায়ন যা এক্সিকিউশন মডেল সহ সিপিইউগুলিকে লক্ষ্য করে যে সীমাবদ্ধ সময়ে অসীম পরিমাণে কাজ করতে পারে না খালি ধ্রুবক অসীম লুপ অপসারণ করার কোনও যৌক্তিকতা নেই। বা এমনকি সাধারণভাবে, সঠিক শব্দটি তাদের "সমাপ্তি ধরে নেওয়া" যেতে পারে কিনা তা সম্পর্কে। যদি কোনও লুপটি শেষ করতে না পারে, তার অর্থ পরবর্তী কোডটি পৌঁছানো যায় না, আপনি গণিত এবং অসীমতা সম্পর্কে কী যুক্তি দেখান এবং কোনও হাইপোথিক্যাল মেশিনে অসীম পরিমাণে কাজ করতে কতক্ষণ সময় লাগে তা বিবেচনা করে না।
তার পরেও, কলং কেবল আইএসও সি অনুগত ডেথস্টেশন 9000 নয়, এটি কার্নেল এবং এমবেডেড স্টাফ সহ বাস্তব-বিশ্বের নিম্ন-স্তরের সিস্টেমের প্রোগ্রামিংয়ের জন্য কার্যকর হওয়ার উদ্দেশ্যে। সুতরাং আপনি সি 11 কে অপসারণের অনুমতি দেওয়ার বিষয়ে যুক্তি স্বীকার করেন বা না while(1);
করেন, এটি বোধগম্য নয় যে কলং আসলে এটি করতে চাইবে। আপনি যদি লিখেন while(1);
, সম্ভবত এটি কোনও দুর্ঘটনা ছিল না। দুর্ঘটনার দ্বারা অসীম শেষ হওয়া লুপগুলি অপসারণ (রানটাইম ভেরিয়েবল কন্ট্রোল এক্সপ্রেশন সহ) দরকারী হতে পারে এবং এটি কম্পাইলাররা এটি করার জন্য অর্থবোধ করে।
এটি বিরল যে আপনি কেবল পরবর্তী বাধা না দেওয়া পর্যন্ত স্পিন করতে চান, তবে আপনি যদি সিতে লিখেন তবে অবশ্যই এটি ঘটবে বলে আপনি প্রত্যাশা করেছেন। (এবং কি করে জিসিসি এবং ঝনঝন ঘটতে, ঝনঝন শব্দ জন্য ব্যতীত অসীম লুপ একটি লেফাফা ফাংশন ভিতরে)।
উদাহরণস্বরূপ, একটি আদিম ওএস কার্নেলের মধ্যে, যখন শিডিয়ুলারের চালানোর কোনও কাজ না থাকে এটি নিষ্ক্রিয় টাস্কটি চালাতে পারে। এটির প্রথম প্রয়োগ হতে পারে while(1);
।
বা কোনও পাওয়ার-সেভিং নিষ্ক্রিয় বৈশিষ্ট্য ছাড়াই হার্ডওয়্যারের জন্য, এটিই কেবলমাত্র বাস্তবায়ন হতে পারে। (2000 এর দশকের গোড়া পর্যন্ত, আমি মনে করি এটি x86 এ বিরল নয়। যদিও hlt
নির্দেশনাটি বিদ্যমান ছিল, আইডি কে এটি সিপিইউগুলিকে স্বল্প-শক্তি নিষ্কলনের অবস্থা শুরু না হওয়া পর্যন্ত অর্থবহ পরিমাণ শক্তি সঞ্চয় করে))