অপরিজ্ঞাত আচরণের শাখাগুলি কি অ্যাক্সেসযোগ্য এবং মৃত কোড হিসাবে অনুকূলিত হতে পারে?


89

নিম্নলিখিত বিবৃতি বিবেচনা করুন:

*((char*)NULL) = 0; //undefined behavior

এটি পরিষ্কারভাবে অনির্ধারিত আচরণকে আহ্বান করে। কোনও প্রদত্ত প্রোগ্রামে এই জাতীয় বক্তব্যটির অস্তিত্বের অর্থ কি পুরো প্রোগ্রামটি অনির্ধারিত হয়েছে বা নিয়ন্ত্রণ প্রবাহ এই বিবৃতিতে আঘাতের পরে কেবল আচরণটি অপরিজ্ঞাত হয়ে যায়?

ব্যবহারকারী কখনও সংখ্যায় প্রবেশ না করায় নিম্নলিখিত প্রোগ্রামটি কি সঠিকভাবে সংজ্ঞায়িত হবে 3?

while (true) {
 int num = ReadNumberFromConsole();
 if (num == 3)
  *((char*)NULL) = 0; //undefined behavior
}

বা ব্যবহারকারী কী প্রবেশ করায় তা সম্পূর্ণ অপরিজ্ঞাত আচরণ নয়?

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

int num = ReadNumberFromConsole();

if (num == 3) {
 PrintToConsole(num);
 *((char*)NULL) = 0; //undefined behavior
}

এখানে, সংকলকটি যুক্তিযুক্ত হতে পারে যে ক্ষেত্রে num == 3আমরা সর্বদা অপরিবর্তিত আচরণের জন্য প্রার্থনা করব। অতএব, এই কেসটি অবশ্যই অসম্ভব এবং সংখ্যাটি মুদ্রণের প্রয়োজন নেই। পুরো ifবিবৃতিটি অপ্টিমাইজ করা যেতে পারে। এই ধরণের পিছনের যুক্তিটি কি স্ট্যান্ডার্ড অনুযায়ী অনুমোদিত?


19
কখনও কখনও আমি ভাবছি যে প্রচুর রেপ সহ ব্যবহারকারীরা যদি প্রশ্নগুলিতে আরও বেশি উত্স পান তবে কারণ "ওহ তাদের প্রচুর রেপ আছে, এটি অবশ্যই একটি ভাল প্রশ্ন" ... তবে এই ক্ষেত্রে আমি প্রশ্নটি পড়েছিলাম এবং ভেবেছিলাম "বাহ, এটি দুর্দান্ত "আমি এমনকি জিজ্ঞাসকের দিকে তাকানোর আগে।
টারবুলেন্সেটো

4
আমি মনে করি যে সময়টি যখন অপরিজ্ঞাত আচরণের উত্থান ঘটে তখন অপরিজ্ঞাত।
এরেরিকা

6
সি ++ স্ট্যান্ডার্ড স্পষ্টতই বলেছে যে যে কোনও সময়ে অপরিজ্ঞাত আচরণের সাথে সম্পাদনের পথ সম্পূর্ণ অপরিজ্ঞাত। আমি এমনকি এটির ব্যাখ্যা দিয়ে বলব যে পথে পথে অপরিজ্ঞাত আচরণ সহ যে কোনও প্রোগ্রাম সম্পূর্ণ অপরিজ্ঞাত (এতে অন্যান্য অংশগুলির মধ্যে যুক্তিসঙ্গত ফলাফল রয়েছে, তবে এটির নিশ্চয়তা নেই)। সংকলকরা আপনার প্রোগ্রামটি সংশোধন করতে অপরিজ্ঞাত আচরণ ব্যবহার করতে পারেন। blog.llvm.org/2011/05/hat-every-c-pogrammer-should- ज्ञान.html এ কিছু চমৎকার উদাহরণ রয়েছে।
জেনস

4
@ জেনস: এটির অর্থ সত্যিকার অর্থে কার্যকর করার পথ। অন্যথায় আপনি সমস্যার মধ্যে পড়ে const int i = 0; if (i) 5/i;
এমসাল্টার

4
সাধারণভাবে সংকলক প্রমাণ করতে PrintToConsoleপারে না std::exitযে এটি কল করে না তাই এটি কল করতে হবে।
MSalters

উত্তর:


66

কোনও প্রদত্ত প্রোগ্রামে এই জাতীয় বক্তব্যটির অস্তিত্বের অর্থ কি পুরো প্রোগ্রামটি অনির্ধারিত হয়েছে বা নিয়ন্ত্রণ প্রবাহ এই বিবৃতিতে আঘাতের পরে কেবল আচরণটি অপরিজ্ঞাত হয়ে যায়?

না। প্রথম অবস্থাটি খুব শক্ত এবং দ্বিতীয়টি খুব দুর্বল।

অবজেক্ট অ্যাক্সেস কখনও কখনও ক্রমযুক্ত হয়, কিন্তু মান সময়ের বাইরে প্রোগ্রামের আচরণ বর্ণনা করে। ড্যানভিল ইতিমধ্যে উদ্ধৃত:

যদি এই জাতীয় নির্বাহের কোনও অপরিজ্ঞাত অপারেশন থাকে তবে এই আন্তর্জাতিক স্ট্যান্ডার্ডটি সেই ইনপুট দিয়ে সেই প্রোগ্রামটি সম্পাদন করে এমন বাস্তবায়নের কোনও প্রয়োজনীয়তা রাখে না (এমনকি প্রথম অপরিবর্তিত অপারেশন পূর্ববর্তী অপারেশনগুলির ক্ষেত্রেও নয়)

এটি ব্যাখ্যা করা যেতে পারে:

যদি প্রোগ্রামটির সম্পাদনটি অনির্ধারিত আচরণের ফলন করে তবে পুরো প্রোগ্রামটিরই নির্ধারিত আচরণ থাকে।

সুতরাং, ইউবির সাথে একটি অপ্রাপ্য বক্তব্য প্রোগ্রামটিকে ইউবি দেয় না। একটি पहुंचযোগ্য বক্তব্য যা (ইনপুটগুলির মানগুলির কারণে) কখনই পৌঁছায় না, প্রোগ্রামটিকে ইউবি দেয় না। এজন্য আপনার প্রথম অবস্থাটি খুব শক্ত।

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

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

আপনি এটি হিসাবে ভাবতে পারেন, "ইউবিতে একটি টাইম মেশিন রয়েছে"।

বিশেষত আপনার উদাহরণগুলির উত্তর দিতে:

  • আচরণটি কেবল 3 টি পড়লে অপরিজ্ঞাত হয়।
  • সংযোগকারীরা কোডটিকে মৃত হিসাবে নির্মূল করতে এবং করতে পারে যদি একটি প্রাথমিক ব্লকে কোনও অপারেশন নির্দিষ্ট না করে নির্দিষ্ট করা থাকে contains এগুলিকে অনুমতি দেওয়া হয়েছে (এবং আমি অনুমান করছি) যেগুলি কোনও প্রাথমিক ব্লক নয় তবে যেখানে সমস্ত শাখাগুলি ইউবির দিকে পরিচালিত করে। এই উদাহরণটি কোনও প্রার্থী নয় যদি না PrintToConsole(3)কোনওভাবে ফিরে আসার বিষয়ে নিশ্চিত হন। এটি একটি ব্যতিক্রম বা যাই হোক না কেন নিক্ষেপ করতে পারে।

আপনার দ্বিতীয়টির মতো একই উদাহরণটি হ'ল জিসিসি বিকল্প -fdelete-null-pointer-checks, যা এই জাতীয় কোড নিতে পারে (আমি এই নির্দিষ্ট উদাহরণটি পরীক্ষা করে দেখিনি, এটি সাধারণ ধারণার উদাহরণস্বরূপ বিবেচনা করুন):

void foo(int *p) {
    if (p) *p = 3;
    std::cout << *p << '\n';
}

এবং এটিকে পরিবর্তন করুন:

*p = 3;
std::cout << "3\n";

কেন? কারণ যদি pএটি নাল হয় তবে কোডটি যাহাই হউক না কেন ইউবি রয়েছে, তাই সংকলকটি ধরে নিতে পারে এটি নাল নয় এবং সেই অনুসারে অনুকূলিত। লিনাক্স কার্নেলটি এটিকে ছাপিয়ে গেছে ( https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1897 ) মূলত কারণ এটি এমন একটি মোডে পরিচালনা করে যেখানে নাল পয়েন্টারকে অবজ্ঞা করার কথা নয় ইউবি হোন, এটির সাহায্যে কার্নেল হ্যান্ডেল করতে পারে এমন একটি সংজ্ঞায়িত হার্ডওয়্যার ব্যতিক্রম হবে। যখন অপ্টিমাইজেশন সক্ষম করা থাকে, তখন গিসি এর -fno-delete-null-pointer-checksমান-এর বাইরে গ্যারান্টি সরবরাহ করার জন্য ব্যবহার প্রয়োজন ।

পিএস এই প্রশ্নের বাস্তবিক উত্তর "কখনই অপরিবর্তিত আচরণটি ধর্মঘট করে?" "আপনি দিনের উদ্দেশ্যে যাত্রা করার 10 মিনিট আগে"।


4
আসলে, অতীতে এই কারণে বেশ কয়েকটি সুরক্ষা সমস্যা ছিল। বিশেষত, বাস্তবের পরে কোনও ওভারফ্লো চেক এর কারণে অপ্টিমাইজড হওয়ার ঝুঁকিতে রয়েছে। উদাহরণ হিসেবে বলা যায় void can_add(int x) { if (x + 100 < x) complain(); }, দূরে সম্পূর্ণভাবে অপ্টিমাইজ করা যাবে না কারণ যদি x+100 ফেলে না ' ওভারফ্লো কিছুই ঘটে, এবং যদি x+100 না ওভারফ্লো, যে মান অনুযায়ী UB, তাই কিছুই পারে ঘটে।
fgp

4
@ এফজিপি: ঠিক আছে, এটি একটি অপ্টিমাইজেশন যা লোকেরা যদি ট্রিপ করে তবে তারা তীব্রভাবে অভিযোগ করবে কারণ এটি মনে হতে শুরু করে যে সংকলক ইচ্ছাকৃতভাবে আপনাকে শাস্তি দেওয়ার জন্য আপনার কোডটি ভঙ্গ করছে। "আপনি যদি এটি সরিয়ে ফেলতে চান তবে আমি কেন সেভাবে এটি লিখতাম!" ;-) তবে আমি মনে করি যে কখনও কখনও বৃহত্তর পাটিগণিতের অভিব্যক্তিগুলিতে হেরফের করার সময় এটি অপ্টিমাইজারের পক্ষে কার্যকর,
স্টিভ জেসোপ

4
এটি কি ঠিক বলা উচিত যে যদি ব্যবহারকারী কখনও 3 টি প্রবেশ না করে তবে প্রোগ্রামটি অপরিজ্ঞাত নয়, তবে যদি তিনি একটি মৃত্যুদন্ড কার্যকর করার সময় 3 টি প্রবেশ করেন পুরো সম্পাদন অপরিজ্ঞাত হয়ে যায়? যত তাড়াতাড়ি এটি 100% নিশ্চিত হয়ে গেছে যে প্রোগ্রামটি অনির্ধারিত আচরণের ডাক দেবে (এবং এর চেয়ে বেশি তাড়াতাড়ি নয়) আচরণকে কিছু হতে দেওয়া হয়। আমার এই বিবৃতিগুলি কি 100% সঠিক?
usr ডিরেক্টরির

4
@ অ্যাসার: আমি বিশ্বাস করি এটি সঠিক, হ্যাঁ। আপনার নির্দিষ্ট উদাহরণের সাথে (এবং ডেটা প্রক্রিয়াজাতকরণের অনিবার্যতা সম্পর্কে কিছু অনুমান করা) আমি মনে করি যে বাস্তবায়ন নীতিগতভাবে 3যদি চাইছিল তবে এটি এসএমএস-এর জন্য বাফার এসটিডিনের সামনে দেখতে পারে এবং এটি যখনই দেখল ততক্ষণে বাড়ির জন্য প্যাক অফ করে দিতে পারে I আগত
স্টিভ জেসপ

4
আপনার PS এর জন্য অতিরিক্ত +1 (যদি আমি পারতাম)
ফ্রেড লারসন

10

1.9 / 4 এ স্ট্যান্ডার্ডটি জানিয়েছে

[দ্রষ্টব্য: এই আন্তর্জাতিক স্ট্যান্ডার্ডটি এমন প্রোগ্রামগুলির আচরণের জন্য কোনও প্রয়োজনীয়তা আরোপ করে না যার মধ্যে অপরিজ্ঞাত আচরণ রয়েছে। - শেষ নোট]

আকর্ষণীয় বিষয় সম্ভবত "ধারণ" এর অর্থ কী means একটু পরে 1.9 / 5 এ বলা হয়েছে:

যাইহোক, যদি এইরকম কোনও কার্যকরকরণের একটি অপরিজ্ঞাত অপারেশন থাকে তবে এই আন্তর্জাতিক স্ট্যান্ডার্ড সেই ইনপুট দিয়ে সেই প্রোগ্রামটি সম্পাদন করে এমন বাস্তবায়ন করার কোনও প্রয়োজন রাখে না (এমনকি প্রথম অপরিবর্তিত অপারেশন পূর্ববর্তী অপারেশনগুলির ক্ষেত্রেও নয়)

এখানে এটি "ইনপুট সহ ... সম্পাদন ... উল্লেখ করেছে"। আমি ব্যাখ্যা করব যে, একটি সম্ভাব্য শাখায় অপরিজ্ঞাত আচরণ যা বর্তমানে কার্যকর করা হয় তা কার্যকর করার বর্তমান শাখাকে প্রভাবিত করে না।

কোড জেনারেশনের সময় অপরিবর্তিত আচরণের উপর ভিত্তি করে একটি ভিন্ন বিষয় হ'ল অনুমানগুলি। সে সম্পর্কে আরও তথ্যের জন্য স্টিভ জেসপের উত্তর দেখুন।


4
যদি আক্ষরিকভাবে নেওয়া হয়, তবে এটিই সমস্ত বাস্তব কর্মসূচির মৃত্যুদণ্ড।
usr ডিরেক্টরির

6
আমি মনে করি না যে আসলে প্রশ্নটি পৌঁছানোর আগেই ইউবি উপস্থিত হতে পারে question প্রশ্নটি যেমনটি আমি বুঝতে পেরেছি তা হল, যদি ইউবি উপস্থিত হতে পারে তবে কোডটিও পৌঁছায় না। এবং অবশ্যই এর উত্তর "না"।
sepp2k

ভাল এই সম্পর্কে 1.9 / 4 এ স্ট্যান্ডার্ডটি এতটা পরিষ্কার নয় তবে 1.9 / 5 সম্ভবত আপনি যা বলেছিলেন তা ব্যাখ্যা করা যেতে পারে।
ড্যানভিল

4
নোটগুলি মানহীন ma 1.9 / 5 নোটটি 1.9 / 4 এ ট্রাম্প করে
এমসাল্টাররা

5

একটি শিক্ষণীয় উদাহরণ

int foo(int x)
{
    int a;
    if (x)
        return a;
    return 0;
}

বর্তমানের জিসিসি এবং বর্তমান কলঙ্ক উভয়ই এটিকে (x86-এ) অনুকূলিত করবে

xorl %eax,%eax
ret

কারণ তারা অনুমান যে xসবসময় শূন্য মধ্যে UB থেকে if (x)নিয়ন্ত্রণ পথ। জিসিসি আপনাকে ব্যবহার-অ-বঞ্চিত-মূল্যবান সতর্কতাও দেবে না! (কারণ উপরের যুক্তি প্রয়োগকারী পাসটি অচিরাচরিত-মান সতর্কতা উত্পন্ন করার আগে পাস হয়)


4
আকর্ষণীয় উদাহরণ। এটি বরং কদর্য যে অপ্টিমাইজেশান সক্ষম করে সতর্কতা লুকায়। এটি এমনকি নথিভুক্ত নয় - জিসিসি ডক্সটি কেবলমাত্র বলে যে অপ্টিমাইজেশান সক্ষম করা আরও সতর্কতা উত্পন্ন করে।
sleske

@ স্লেসেকে এটা দুষ্টু, আমি সম্মত, কিন্তু অবিচ্ছিন্ন মূল্যের সতর্কতাগুলি "ডান পাওয়া" কুখ্যাতভাবে - এগুলি নিখুঁতভাবে করা হ্যালটিং সমস্যার সমতুল্য, এবং প্রোগ্রামাররা মিথ্যা ইতিবাচকতা ঘটাতে "অপ্রয়োজনীয়" পরিবর্তনশীল সূচনা সংযোজন সম্পর্কে অদ্ভুতভাবে যুক্তিযুক্ত হয়, তাই সংকলক লেখকরা ব্যারেলের উপর দিয়ে গেছে। আমি জিসিসিতে হ্যাক করতাম এবং আমি স্মরণ করি যে প্রত্যেকে অবিচ্ছিন্ন-মান-সতর্কতার পাস দিয়ে গোলযোগ করতে ভয় পেয়েছিল।
zwol

@ জওয়ল: আমি অবাক হয়েছি যে এই জাতীয় ডেড-কোড নির্মূলের ফলে প্রাপ্ত "অপ্টিমাইজেশন "টি আসলে দরকারী কোডকে আরও ছোট করে তোলে এবং প্রোগ্রামাররা কোডকে আরও বড় করে তোলার কারণ হয়ে থাকে (উদাহরণস্বরূপ aসকল পরিস্থিতিতে এমনকি কোড শুরু করার পরে কোডটি যুক্ত করে যেখানে একটি অবিচ্ছিন্নভাবে aফাংশনে পাস হয়ে যাবে যে ফাংশনটি এর সাথে কিছুই করবে না)?
সুপারক্যাট

@ সুপের্যাট আমি 10 বছরের মধ্যে সংকলক কাজের সাথে গভীরভাবে জড়িত ছিলাম না, এবং খেলনা উদাহরণ থেকে অপ্টিমাইজেশান সম্পর্কে যুক্তিযুক্ত করা প্রায় অসম্ভব। এই ধরণের অপ্টিমাইজেশান প্রকৃত অ্যাপ্লিকেশনগুলিতে 2-5% সামগ্রিক কোড-আকার হ্রাসের সাথে যুক্ত হতে থাকে, যদি আমি সঠিকভাবে মনে করি।
zwol

4
এই জিনিসগুলি যেমন যান তেমন @supercat 2-5% বিশাল । আমি 0.1% এর জন্য লোকদের ঘাম দেখেছি।
zwol

4

বর্তমান সি ++ কার্যকারী খসড়াটি 1.9.4 এ বলেছে

এই আন্তর্জাতিক স্ট্যান্ডার্ডটি এমন প্রোগ্রামগুলির আচরণের জন্য কোনও প্রয়োজনীয়তা চাপায় না যেখানে অনুলিখিত আচরণ থাকে।

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

অপরিবর্তিত আচরণ এবং দুটি সংকলক সাধারণত কি করেন সে সম্পর্কে দুটি সত্যই নিবন্ধ রয়েছে:


4
ওটা কোন অর্থ প্রকাশ করে না. ফাংশন int f(int x) { if (x > 0) return 100/x; else return 100; }অবশ্যই অনির্ধারিত আচরণকে কখনই ডাকে না, যদিও 100/0অবশ্যই এটি অপরিজ্ঞাত।
fgp

4
@fgp কি মান (বিশেষ করে 1.9 / 5) এরশাদ করেন, যদিও, যে যদি অনির্ধারিত আচরণ করতে পৌঁছে যেতে, তাই না ব্যাপার যখন এটা উপনিত। উদাহরণস্বরূপ, printf("Hello, World"); *((char*)NULL) = 0 করা হয় না কিছু প্রিন্ট করতে নিশ্চিত। এটি অপ্টিমাইজেশনকে সহায়তা করে, কারণ সংকলকটি নির্বিঘ্নে পুনরায় ক্রম পরিচালনা করতে পারে (নির্ভরতার সীমাবদ্ধতার অধীন, অবশ্যই) এটি জানে যে অবশেষে ঘটবে, অ্যাকাউন্টে অনির্ধারিত আচরণ না নিয়েই।
fgp

আমি বলব যে আপনার ফাংশন সহ কোনও প্রোগ্রামে অপরিজ্ঞাত আচরণ নেই, কারণ এমন কোনও ইনপুট নেই যেখানে 100/0 মূল্যায়ন করা হবে।
জেনস

4
হুবহু - সুতরাং কী বিষয়টি ইউबीকে আসলে ট্রিগার করা যায় কিনা তা তাত্ত্বিকভাবে ট্রিগার করা যায় কিনা তা নয় । অথবা আপনি int x,y; std::cin >> x >> y; std::cout << (x+y);যে "1 + 1 = 17" বলার অনুমতি পেয়েছেন তা তর্ক করার জন্য প্রস্তুত , কারণ সেখানে কিছু ইনপুট রয়েছে যেখানে x+yওভারফ্লো হয় (যা intএকটি স্বাক্ষরিত ধরণের যা থেকে ইউবি )।
fgp

আনুষ্ঠানিকভাবে, আমি বলব যে প্রোগ্রামটির অপরিবর্তিত আচরণ রয়েছে কারণ সেখানে এমন ইনপুট রয়েছে যা এটি ট্রিগার করে। তবে আপনি ঠিক বলেছেন যে এটি সি ++ এর প্রসঙ্গে উপলব্ধি করতে পারে না, কারণ অপরিজ্ঞাত আচরণ ছাড়া কোনও প্রোগ্রাম লেখা অসম্ভব। আমি চাই যখন সি ++ তে কম অপরিজ্ঞাত আচরণ ছিল, তবে ভাষাটি কীভাবে কাজ করে না (এবং এর কয়েকটি ভাল কারণ আছে তবে তারা আমার দৈনন্দিন ব্যবহারের বিষয়ে চিন্তা করে না ...)।
জেনস

3

শব্দ "ব্যবহার" মানে কিছু হচ্ছে সম্পন্ন । কোনও রাষ্ট্রায়ত্ত যে কখনও মৃত্যুদণ্ড কার্যকর হয় না তা "আচরণ" নয়।

একটি দৃষ্টান্ত:

*ptr = 0;

এটাই কি অপরিজ্ঞাত আচরণ? ধরুন আমরা ptr == nullptrপ্রোগ্রামের প্রয়োগের সময় কমপক্ষে একবার 100% নিশ্চিত হয়েছি । উত্তরটি হ্যাঁ হওয়া উচিত।

এই সম্পর্কে কি?

 if (ptr) *ptr = 0;

এটা কি অপরিজ্ঞাত? ( ptr == nullptrঅন্তত একবার মনে রাখবেন ?) আমি নিশ্চিত আশা করি না, অন্যথায় আপনি কোনও কার্যকর প্রোগ্রাম লিখতে সক্ষম হবেন না।

এই উত্তরটি তৈরিতে কোনও শ্রেন্দারিজকে ক্ষতি করা হয়নি।


3

অপরিবর্তিত আচরণটি যখন কর্মসূচির কারণে হ'ল তারপরে যা ঘটেছিল তা নির্ধারিত আচরণের কারণ হয়। যাইহোক, আপনি নিম্নলিখিত উদাহরণ দিয়েছেন।

int num = ReadNumberFromConsole();

if (num == 3) {
 PrintToConsole(num);
 *((char*)NULL) = 0; //undefined behavior
}

সংকলক সংজ্ঞাটি PrintToConsoleনা জানলে এটি if (num == 3)শর্তসাপেক্ষে অপসারণ করতে পারে না । আসুন ধরে নেওয়া যাক আপনার LongAndCamelCaseStdio.hনীচের ঘোষণার সাথে সিস্টেম শিরোনাম আছে PrintToConsole

void PrintToConsole(int);

কিছুই খুব সহায়ক, ঠিক আছে। এখন, আসুন দেখি যে এই ফাংশনের আসল সংজ্ঞাটি পরীক্ষা করে বিক্রেতা কীভাবে খারাপ (বা সম্ভবত এতটা খারাপ নয়, অপরিজ্ঞাত আচরণটি আরও খারাপ হতে পারে)।

int printf(const char *, ...);
void exit(int);

void PrintToConsole(int num) {
    printf("%d\n", num);
    exit(0);
}

সংকলকটিকে প্রকৃতপক্ষে ধরে নিতে হবে যে কোনও স্বেচ্ছাসেবী ফাংশন সংকলক জানে না এটি কী করে তা কীভাবে প্রস্থান করতে পারে বা একটি ব্যতিক্রম নিক্ষেপ করতে পারে (সি ++ এর ক্ষেত্রে)। আপনি লক্ষ্য করতে পারেন যে *((char*)NULL) = 0;মৃত্যুদন্ড কার্যকর করা হবে না, কারণ মৃত্যুর পরে PrintToConsoleকল কার্যকর হওয়ার পরে চলবে ।

PrintToConsoleবাস্তবে ফিরে আসার সময় অপরিজ্ঞাত আচরণটি আঘাত হানে । সংকলকটি এটি না হওয়ার প্রত্যাশা করে (যেহেতু এটি প্রোগ্রামটি যাই হোক না কেন নির্ধারিত আচরণ কার্যকর করতে পারে), তাই কিছু ঘটতে পারে।

যাইহোক, আসুন অন্য কিছু বিবেচনা করা যাক। ধরা যাক আমরা নাল চেক করছি এবং নাল চেকের পরে ভেরিয়েবলটি ব্যবহার করব।

int putchar(int);

const char *warning;

void lol_null_check(const char *pointer) {
    if (!pointer) {
        warning = "pointer is null";
    }
    putchar(*pointer);
}

এই ক্ষেত্রে, এটি সহজেই লক্ষ্য করা যায় lol_null_checkযেটির জন্য একটি নন-নুল পয়েন্টার প্রয়োজন। বিশ্বব্যাপী অ-উদ্বায়ী warningভেরিয়েবলকে অর্পণ করা এমন কিছু নয় যা প্রোগ্রামটি থেকে বেরিয়ে আসতে পারে বা কোনও ব্যতিক্রম ছুঁড়ে ফেলতে পারে। pointerএছাড়াও অনুদ্বায়ী, তাই এটি না জাদুর এর মান ফাংশন মাঝখানে (যদি এটা আছে, এটা অনির্ধারিত আচরণ) পরিবর্তন করতে পারেন। কলিং lol_null_check(NULL)অপরিজ্ঞাত আচরণের কারণ ঘটায় যা ভেরিয়েবলকে নির্ধারিত না করার কারণ হতে পারে (কারণ এই মুহুর্তে, প্রোগ্রামটি অনির্ধারিত আচরণটি কার্যকর করে তা জানা যায়)।

তবে অপরিবর্তিত আচরণের অর্থ প্রোগ্রামটি যে কোনও কিছু করতে পারে। অতএব, কিছুই নির্ধারিত আচরণটি সময়ের সাথে ফিরে যাওয়া এবং মৃত্যুদন্ড কার্যকর করার প্রথম লাইনের আগে আপনার প্রোগ্রামটিকে ক্রাশ করা থেকে বিরত রাখে int main()। এটি অপরিবর্তিত আচরণ, এটি বোঝার দরকার নেই। এটি 3 টাইপ করার পরেও ক্র্যাশ হয়ে যেতে পারে, তবে অপরিজ্ঞাত আচরণটি সময় মতো ফিরে আসবে এবং আপনার টাইপ 3 করার আগে ক্র্যাশ হবে And যখন আপনার অপরিবর্তিত প্রোগ্রামটি চলছে না।


সমস্ত বৈধ পয়েন্ট। PrintToConsoleএটি এমন একটি প্রোগ্রাম-বহিরাগত পার্শ্ব-প্রতিক্রিয়া serোকানোর আমার প্রচেষ্টা যা ক্রাশ হওয়ার পরেও দৃশ্যমান এবং দৃ strongly়ভাবে ক্রমযুক্ত। আমি এমন পরিস্থিতি তৈরি করতে চেয়েছিলাম যেখানে এই বিবৃতিটি অপ্টিমাইজড হয়েছে কিনা তা আমরা নিশ্চিত করে বলতে পারি। তবে আপনি ঠিক বলেছেন যে এটি কখনই ফিরে আসবে না; আপনার বিশ্বব্যাপী লেখার উদাহরণটি অন্যান্য অপ্টিমাইজেশনের সাথে সম্পর্কিত হতে পারে যা ইউবির সাথে সম্পর্কিত নয়। উদাহরণস্বরূপ একটি অব্যবহৃত গ্লোবাল মুছতে পারে। নিয়ন্ত্রণ ফিরে পাওয়ার নিশ্চয়তা দেওয়া যায় এমন উপায়ে বাহ্যিক পার্শ্ব-প্রতিক্রিয়া তৈরি করার জন্য আপনার কী ধারণা আছে?
usr ডিরেক্টরির

কোনও বাইরের-বিশ্ব-পর্যবেক্ষণযোগ্য পার্শ্ব-প্রতিক্রিয়া কি কোড দ্বারা উত্পাদিত হতে পারে যা সংকলক রিটার্ন অনুমান করতে মুক্ত হবে? আমার বোঝার দ্বারা, এমনকি একটি পদ্ধতি যা কেবলমাত্র একটি volatileচলক পড়ে তা বৈধভাবে আই / ও অপারেশন ট্রিগার করতে পারে যা তত্ক্ষণাত বর্তমান থ্রেডকে বাধা দিতে পারে; বাধা হ্যান্ডলারটি এর পরে আর কিছু করার সুযোগ পাওয়ার আগে থ্রেডটি মেরে ফেলতে পারে। আমি কোনও যৌক্তিকতা দেখতে পাচ্ছি না যার মাধ্যমে সংকলক সেই বিন্দুটির পূর্বে অপরিবর্তিত আচরণকে ধাক্কা দিতে পারে।
সুপারক্যাট

সি স্ট্যান্ডার্ডের দৃষ্টিকোণ থেকে, কম্পিউটারকে কিছু লোকের কাছে একটি বার্তা প্রেরণ করে যা অপ্রকাশিত আচরণের কারণ হিসাবে প্রোগ্রামটির পূর্ববর্তী ক্রিয়াকলাপের সমস্ত প্রমাণগুলি সন্ধান করে এবং ধ্বংস করে দেয়, এমন কোনও অবৈধ কিছুই থাকবে না, তবে যদি কোনও ক্রিয়া কোনও থ্রেডকে বন্ধ করতে পারে, তবে যে ক্রমের আগে ক্রমযুক্ত সমস্ত কিছু তার পরে সংঘটিত কোনও অনির্ধারিত আচরণের আগে ঘটতে হবে।
সুপারক্যাট

1

যদি প্রোগ্রামটি এমন কোনও বিবৃতিতে পৌঁছায় যা অনির্ধারিত আচরণের ডাক দেয়, প্রোগ্রামের আউটপুট / আচরণের কোনওটির জন্য কোনও প্রয়োজনীয়তা স্থাপন করা হয় না; তারা "পূর্বে" বা "পরে" অপরিবর্তিত আচরণ শুরু হওয়ার পরে তা গ্রহণ করবে না।

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


4
কৌতূহলের বাইরে, কখন থেকে __builtin_unreachable()প্রভাবগুলি শুরু হয়েছিল যা সময়ের সাথে পিছনে এবং এগিয়ে উভয়ই এগিয়ে গেছে? প্রদত্ত এমন কিছু দেওয়া যেমন extern volatile uint32_t RESET_TRIGGER; void RESET(void) { RESET_TRIGGER = 0xAA55; __memorybarrier(); __builtin_unreachable(); }আমি দেখতে পেলাম builtin_unreachable()সংকলকটি এটি returnনির্দেশটি বাদ দিতে পারে তা জানার পক্ষে এটি ভাল , তবে এটি পূর্ববর্তী কোড বাদ দেওয়া যেতে পারে তার চেয়ে আলাদা।
সুপারক্যাট

@ সুপারক্র্যাট যেহেতু RESET_TRIGGER অস্থির, সেই জায়গাগুলিতে লেখার ইচ্ছামত পার্শ্ব প্রতিক্রিয়া হতে পারে। সংকলকটির কাছে এটি একটি অস্বচ্ছ পদ্ধতি কলের মতো। অতএব, এটি __builtin_unreachableপৌঁছানো প্রমাণিত হতে পারে না (এবং এটি কেস নয়) । এই প্রোগ্রাম সংজ্ঞায়িত করা হয়।
usr ডিরেক্টরির

@ অ্যাসার: আমি ভাবব যে নিম্ন-স্তরের সংকলকগুলি অস্বচ্ছ প্রবেশাধিকারকে অস্বচ্ছ পদ্ধতি কল হিসাবে বিবেচনা করা উচিত, তবে ঝনঝন বা জিসিসি উভয়ই তা করে না। অন্যান্য বিষয়গুলির মধ্যে, একটি অস্বচ্ছ পদ্ধতি কল কোনও কারণের বাইরের বিশ্বের কাছে প্রকাশিত হয়েছে এমন কোনও বস্তুর সমস্ত বাইটের কারণ হতে পারে, এবং যা কোনও লাইভ restrictপয়েন্টার দ্বারা অ্যাক্সেস করা যায় নি বা ব্যবহার করা যাবে না, এটি একটি ব্যবহার করে লেখা যেতে পারে unsigned char*
সুপারক্যাট

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

@ সুপের্যাট আমার মনে হয় আপনি ঠিক বলেছেন দেখে মনে হচ্ছে অস্থির অপারেশনগুলির "অ্যাবস্ট্রাক্ট মেশিনে কোনও প্রভাব নেই" এবং তাই প্রোগ্রামটি শেষ করতে বা পার্শ্ব প্রতিক্রিয়া সৃষ্টি করতে পারে না।
usr

1

আইইটিএফ আরএফসি 2119 (যদিও সেই নথির সংজ্ঞাগুলি উদ্ধৃত করার প্রয়োজন নেই) এর সংজ্ঞা অনুসারে নাম ব্যবহার করে বাস্তবায়ন করা উচিত বা প্রয়োগ করা উচিত না এমন বিষয়গুলি বর্ণনা করার জন্য বিভিন্ন ধরণের জিনিসের অনেকগুলি স্ট্যান্ডার্ড প্রচুর পরিশ্রম ব্যয় করে । অনেক ক্ষেত্রে, বাস্তবায়নের যে জিনিসগুলি অকেজো বা অযৌক্তিক হবে সেগুলি ব্যতীত যেগুলি প্রয়োগ করা উচিত তাদের বিবরণগুলি প্রয়োজনীয়গুলির চেয়ে বেশি গুরুত্বপূর্ণ যা সমস্ত বাস্তবায়নের সাথে সঙ্গতিপূর্ণ ।

দুর্ভাগ্যক্রমে, সি এবং সি ++ স্ট্যান্ডার্ডগুলি এমন কিছুর বিবরণগুলি রক্ষা করতে প্রবণতা বোধ করে যা 100% প্রয়োজনীয় নয়, তবুও মান বাস্তবায়নের প্রত্যাশা করা উচিত যা বিপরীত আচরণের দলিল দেয় না। বাস্তবায়নগুলি কিছু করা উচিত এমন একটি পরামর্শ অবশ্যই বোঝানো যেতে পারে যেগুলি নিম্নমানের নয় এবং যে ক্ষেত্রে সাধারণত স্পষ্টভাবে বোঝা যায় যে কোন আচরণ কার্যকর বা ব্যবহারিক, বনাম অবৈজ্ঞানিক এবং অকেজো, কোনও নির্দিষ্ট প্রয়োগের ক্ষেত্রে কার্যকর ছিল? স্ট্যান্ডার্ডের এই জাতীয় রায়গুলিতে হস্তক্ষেপ করার জন্য সামান্য বোধ করা দরকার।

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


এটি একটি ভাল বিষয় যে ইউবি এড়িয়ে চলা ব্যবহারকারী কোডে একটি ব্যয় চাপিয়ে দিতে পারে ।
usr ডিরেক্টরির

@ অ্যাসার: এটি এমন একটি বিষয় যা আধুনিকতাবাদীরা পুরোপুরি হাতছাড়া করে। আমি একটি উদাহরণ যুক্ত করা উচিত? যেমন কোড নির্ণয় করা প্রয়োজন যদি x*y < zযখন x*yওভারফ্লো না, এবং ওভারফ্লো ফলন পারেন 0 বা 1 নির্বিচারে ফ্যাশন কিন্তু পার্শ্ব প্রতিক্রিয়া ছাড়া ক্ষেত্রে, সেখানে সবচেয়ে প্ল্যাটফর্মের উপর কোনো কারণ নেই কেন দ্বিতীয় ও তৃতীয় প্রয়োজনীয়তা পূরণের বেশী ব্যয়বহুল হওয়া উচিত প্রথমটির সাথে সাক্ষাত করা, তবে সমস্ত ক্ষেত্রে মান-সংজ্ঞায়িত আচরণের গ্যারান্টি হিসাবে অভিব্যক্তি লেখার যে কোনও উপায়ে কিছু ক্ষেত্রে উল্লেখযোগ্য ব্যয় যুক্ত হবে। (int64_t)x*y < zগণনা
ব্যয়কে

... কিছু প্ল্যাটফর্মে, এবং এটি রচনা লিখতে (int)((unsigned)x*y) < zকোনও সংকলককে অন্যথায় দরকারী বীজগণিত বিকল্পগুলি হতে পারে এমন কাজে লাগানো থেকে বিরত রাখে (যেমন যদি এটি জানে xএবং zসমান এবং ধনাত্মক হয় তবে এটি মূল অভিব্যক্তিটিকে সহজতর করতে পারে y<0তবে স্বাক্ষরবিহীন সংস্করণ ব্যবহার করে সংকলককে গুণিত করতে বাধ্য করবে)। যদি সংকলক গ্যারান্টি দিতে পারে যদিও স্ট্যান্ডার্ড এটি আদেশ না দেয় তবে এটি "কোনও পার্শ্ব-প্রতিক্রিয়া ছাড়াই 0 বা 1 ফলন" সমুন্নত রাখবে, ব্যবহারকারী কোডটি অন্যথায় নাও পেতে পারে এমন সংকলক অপটিমাইজেশন সুযোগ দিতে পারে।
সুপারক্যাট

হ্যাঁ, মনে হচ্ছে এখানে কিছু হালকা ফর্ম অপরিজ্ঞাত আচরণটি সহায়ক হবে। প্রোগ্রামার এমন একটি মোড চালু করতে পারে x*yযা অতিরিক্ত প্রবাহের ক্ষেত্রে একটি সাধারণ মান তবে যে কোনও মানকেই নির্গত করে। সি / সি ++ এ কনফিগারযোগ্য ইউবি আমার কাছে গুরুত্বপূর্ণ বলে মনে হচ্ছে।
usr

@ ইউএসআর: সি 98 স্ট্যান্ডার্ডের লেখকরা যদি এই কথাটি সত্যবাদী হয়ে থাকেন যে স্বাক্ষরিত স্বাক্ষরিত স্বল্প স্বাক্ষরিত মানগুলিকে প্রচার করা সবচেয়ে মারাত্মক ব্রেকিং পরিবর্তন, এবং অজ্ঞ বোকা না ছিল, তবে এর অর্থ এই হবে যে তারা প্ল্যাটফর্মগুলির ক্ষেত্রে এমন প্রত্যাশা করেছিল যে দরকারী আচরণগত গ্যারান্টি সংজ্ঞায়িত করা হচ্ছে, এই জাতীয় প্ল্যাটফর্মগুলির জন্য বাস্তবায়নগুলি সেই গ্যারান্টিগুলি প্রোগ্রামারদের জন্য উপলব্ধ করে তুলেছিল এবং প্রোগ্রামাররা তাদের শোষণ করে চলেছিল , স্ট্যান্ডার্ড তাদের আদেশ দিয়েছে কিনা তা এই জাতীয় প্ল্যাটফর্মগুলির সংকলকরা এই ধরনের আচরণগত গ্যারান্টি সরবরাহ করতে থাকবে
সুপারক্যাট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.