স্যুইচ স্টেটমেন্টটি কেন একটি বিরতির প্রয়োজনের জন্য ডিজাইন করা হয়েছিল?


139

একটি সাধারণ সুইচ বিবৃতি দেওয়া

switch (int)
{
    case 1 :
    {
        printf("1\n");
        break;
    }

    case 2 : 
    {
        printf("2\n");
    }

    case 3 : 
    {
        printf("3\n");
    }
}

2 ক্ষেত্রে ব্রেক স্টেটমেন্টের অনুপস্থিতি বোঝায় যে 3 এর ক্ষেত্রে কোডের মধ্যে ফাঁসি কার্যকর থাকবে This এটি কোনও দুর্ঘটনা নয়; এটি সেভাবে ডিজাইন করা হয়েছিল। কেন এই সিদ্ধান্ত নেওয়া হয়েছিল? এটি ব্লকগুলির জন্য একটি স্বয়ংক্রিয় বিরতি শব্দার্থক থাকার বনাম কী সরবরাহ করে? যুক্তি কী ছিল?

উত্তর:


150

অনেক উত্তর বিবৃতি প্রয়োজনীয়তার কারণ হিসাবে পড়ার ক্ষমতা উপর ফোকাস বলে মনে হচ্ছে break

আমি বিশ্বাস করি এটি কেবল একটি ভুল ছিল, মূলত কারণ সি এর নকশা করা হয়েছিল তখন এই নির্মাণগুলি কীভাবে ব্যবহৃত হবে সে সম্পর্কে প্রায় ততটা অভিজ্ঞতা ছিল না।

পিটার ভ্যান ডের লিন্ডেন তাঁর "বিশেষজ্ঞ সি প্রোগ্রামিং" বইটিতে মামলাটি করেছেন:

আমরা কতবার ডিফল্ট পতনের মধ্য দিয়ে ব্যবহৃত হত তা দেখতে সান সি সংকলক উত্স বিশ্লেষণ করেছি। সান এএনএসআই সি সংকলক সামনের প্রান্তে 244 সুইচ স্টেটমেন্ট রয়েছে, যার প্রত্যেকটিতে গড়ে সাতটি কেস রয়েছে। এই সমস্ত ক্ষেত্রে মাত্র 3% এর মধ্যে পড়ে।

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

switch (operator->num_of_operands) {
    case 2: process_operand( operator->operand_2);
              /* FALLTHRU */

    case 1: process_operand( operator->operand_1);
    break;
}

কেস ফ্যাল এর মাধ্যমে এত ত্রুটি হিসাবে ব্যাপকভাবে স্বীকৃতি পেয়েছে যে উপরে দেখানো একটি বিশেষ মন্তব্য সম্মেলনও রয়েছে যা লিঙ্ককে বলে যে "এটি সত্যিকারের সেই 3% ক্ষেত্রেই দেখা যায় যেখানে পড়ে যাওয়ার ইচ্ছা ছিল।"

আমি মনে করি যে প্রতিটি কেস ব্লকের শেষে (# একাধিক কেস লেবেল সজ্জিত করার অনুমতি দেওয়ার পরে - যতক্ষণ না কেবলমাত্র বিবৃতিগুলির একক ব্লক রয়েছে) সি'র পক্ষে সুস্পষ্ট জাম্পের বিবৃতি প্রয়োজন। সি # তে আপনার এখনও একটি কেস অন্য ক্ষেত্রে পড়তে পারে - আপনি কেবল একটি ব্যবহার করে পরবর্তী কেসটিতে ঝাঁপিয়ে পড়ে স্পষ্ট করে দিতে হবে goto

এটা খুব খারাপ জাভা সি শব্দার্থবিজ্ঞান থেকে বিরতি সুযোগ নেয় নি।


প্রকৃতপক্ষে, আমি তাদের বাস্তবায়নের সরলতার জন্য বলে মনে করি। কিছু অন্যান্য ভাষা সম্ভবত দক্ষতার জন্য আরও পরিশীলিত কেস (ব্যাপ্তি, একাধিক মান, স্ট্রিং ...) সমর্থন করে।
ফিলিহো

জাভা সম্ভবত অভ্যাস ভাঙতে এবং বিভ্রান্তি ছড়াতে চায় নি। ভিন্ন আচরণের জন্য তাদের বিভিন্ন শব্দার্থবিজ্ঞান ব্যবহার করতে হবে। জাভা ডিজাইনাররা যাইহোক, সি থেকে বিচ্ছিন্ন হওয়ার জন্য বেশ কয়েকটি সুযোগ হারিয়েছেন।
ফিলিহো

@ ফিলিহো - আমি মনে করি আপনি সম্ভবত "বাস্তবায়নের সরলতা" দিয়ে সত্যের নিকটতম।
মাইকেল বুড়

আপনি যদি GOTO এর মাধ্যমে সুস্পষ্ট জাম্প ব্যবহার করছেন, কেবলমাত্র আইএফ স্টেটমেন্টের একটি সিরিজ ব্যবহার করা ঠিক ততটাই উত্পাদনশীল নয়?
ডিভিনবি

3
এমনকি পাস্কাল বিনা বিরতিতে তাদের স্যুইচ প্রয়োগ করে। সি সংকলক-কোডার এটি সম্পর্কে কীভাবে ভাবতে পারে না @@
চ্যান লে

30

অনেক উপায়ে সি মানক সমাবেশের প্রতিমাগুলির এক পরিষ্কার ইন্টারফেস। জাম্প টেবিল চালিত ফ্লো কন্ট্রোল লেখার সময় প্রোগ্রামারটির "নিয়ন্ত্রণ কাঠামো" থেকে ঝাঁপিয়ে পড়া বা লাফিয়ে যাওয়ার পছন্দ থাকে এবং জাম্প আউটের একটি সুস্পষ্ট নির্দেশনার প্রয়োজন হয়।

সুতরাং, সি একই জিনিস করে ...


1
আমি জানি অনেক লোক এটি বলে তবে আমি মনে করি এটি সম্পূর্ণ চিত্র নয়; সি অ্যাসেম্বলি অ্যান্টিপ্যাটার্নগুলির প্রায়শই একটি কুরুচিপূর্ণ ইন্টারফেসও হয়। 1. কুরুচিপূর্ণ: বিবৃতি পরিবর্তে বিবৃতি। "ঘোষণা ব্যবহারের প্রতিফলন ঘটায়।" যেমন পবিত্র কপি-পেস্ট modularity এর এবং বহনযোগ্যতা জন্য প্রক্রিয়া। প্রকার সিস্টেম পথ খুব জটিল; বাগ উত্সাহ দেয় । । (পরবর্তী মন্তব্যে অবিরত))NULL
হ্যারিসন

২. অ্যান্টিপ্যাটার্নস: "ক্লিন" ট্যাগযুক্ত ইউনিয়ন সরবরাহ করে না, সমাবেশের দুটি মৌলিক তথ্য-উপস্থাপনের আইডিয়ামগুলির মধ্যে একটি। (নূথ, খণ্ড ১ ম, সিএইচ 2) পরিবর্তে, "অবিকৃত ইউনিয়নগুলি," একটি অ-প্রতিচ্ছবির হ্যাক। এই পছন্দটি কয়েক দশক ধরে লোকেরা যেভাবে ডেটা নিয়ে চিন্তা করে তা আটকে রেখেছে। এবং NULনির্ধারিত স্ট্রিংগুলি এখন পর্যন্ত সবচেয়ে খারাপ ধারণা।
হ্যারিসন

@ হারিসনক্লাপারম্যান: স্ট্রিংগুলি সংরক্ষণের কোনও পদ্ধতিই সঠিক নয়। নাল-টার্মিনেটেড স্ট্রিংগুলির সাথে যুক্ত বিপুল সংখ্যক সমস্যা দেখা দেয় না যদি রুটিনগুলি গ্রহণ করে যে স্ট্রিংগুলি সর্বাধিক দৈর্ঘ্যের পরামিতি গ্রহণ করে এবং এমন রুটিনগুলির সাথে ঘটে যেগুলি বাফার-আকারের প্যারামিটার গ্রহণ না করে স্থির আকারের বাফারে দৈর্ঘ্যযুক্ত চিহ্নিত স্ট্রিংগুলি সঞ্চয় করে would । স্যুইচ স্টেটমেন্টের নকশা যেখানে কেবলমাত্র লেবেল থাকে তা আধুনিক চোখের কাছে দেখতে অদ্ভুত মনে হতে পারে তবে এটি ফোর্টরান DOলুপের নকশার চেয়ে খারাপ নয় ।
সুপারক্যাট

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

2
যদিও আজকাল লোকেরা নিজেকে নিজের পায়ে গুলি করা থেকে বিরত রাখে এমন আইডো এবং ভাষার বৈশিষ্ট্যগুলি পরিষ্কার এবং স্ব-সুরক্ষার জন্য বেশি ব্যবহৃত হয়, এটি এমন একটি অঞ্চলের একটি স্মৃতি যেখানে বাইটগুলি ব্যয়বহুল ছিল (সি 1970 এর আগে শুরু হয়েছিল)। যদি আপনার কোডটি 1024 বাইটের মধ্যে ফিট করতে হয় তবে আপনি কোডের টুকরোগুলি পুনরায় ব্যবহার করতে ভারী প্রস্তুতি অনুভব করবেন। একই এন্ট্রিপয়েন্টগুলিতে একই প্রান্তে ভাগ করে কোডটি পুনরায় ব্যবহার করা এটি অর্জনের একটি প্রক্রিয়া।
আরপিপি

23

ডাফের ডিভাইসটি প্রয়োগ করতে, অবশ্যই:

dsend(to, from, count)
char *to, *from;
int count;
{
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}

3
আমি ডাফের ডিভাইসটি পছন্দ করি। তাই মার্জিত এবং দুষ্ট দ্রুত।
ডিক্রোস

7
হ্যাঁ, তবে কি প্রতিবার এসও-তে কোনও সুইচ স্টেটমেন্ট আছে তা দেখাতে হবে?
বিলজামেদেব

আপনি দুটি বন্ধ কোঁকড়া ধনুর্বন্ধনী ;-) মিস করেছেন।
টুন ক্রিজেথ

18

যদি মামলাগুলি স্পষ্টভাবে ভাঙ্গার জন্য ডিজাইন করা হয় তবে আপনি পতন হতে পারবেন না।

case 0:
case 1:
case 2:
    // all do the same thing.
    break;
case 3:
case 4:
    // do something different.
    break;
default:
    // something else entirely.

যদি স্যুইচটি প্রতিটি ক্ষেত্রে পরে নিখুঁতভাবে বিভক্ত করার জন্য ডিজাইন করা হয় তবে আপনার এটির কোনও পছন্দ হবে না। স্যুইচ-কেস স্ট্রাকচারটি আরও নমনীয় হওয়ার জন্য ডিজাইন করা হয়েছিল।


12
আপনি একটি স্যুইচ ইমেজ করতে পারেন যা স্পষ্টভাবে বিরতি দেয় তবে এর একটি "ফলথ্রু" কীওয়ার্ড রয়েছে। বিশ্রী, কিন্তু কার্যক্ষম।
dmckee --- প্রাক্তন-মডারেটর বিড়ালছানা

কীভাবে ভাল হবে? আমি "কেস প্রতি কোডের ব্লক" এর চেয়ে বেশি বার এইভাবে কাজ করার জন্য কেস স্টেটমেন্টটি কল্পনা করব ... এটি যদি তবে / অন্যথায় / অন্য ব্লক হয়।
বিলজামেদেব

আমি প্রশ্নটিতে এটিকে যুক্ত করব, প্রতিটি ক্ষেত্রে ব্লকের স্কোপগুলি {। বিভ্রান্তিতে যুক্ত করছে যেহেতু এটি "সময়" বিবৃতিটির শৈলীর মতো দেখায়।
ম্যাথু স্মিথ

1
@ বিল: এটি আরও খারাপ হবে বলে আমি মনে করি, তবে এটি মাইক বি দ্বারা উত্থাপিত অভিযোগের সমাধান করবে: যে পতন হলেও (একাধিক ক্ষেত্রে একই ঘটনা) একটি বিরল ঘটনা এবং এটি ডিফল্ট আচরণ নয়।
dmckee --- প্রাক্তন-মডারেটর বিড়ালছানা

1
আমি ব্রিভিটির জন্য ধনুর্বন্ধনীগুলি রেখেছিলাম, একাধিক বিবৃতি দিয়ে সেগুলি হওয়া উচিত। আমি সম্মত হই যে মামলাগুলি হুবহু একই রকম হলে ফলস্রুটি ব্যবহার করা উচিত। পূর্ববর্তী কেসগুলি ফলথ্রু ব্যবহার করে তৈরি করলে এটি নরক হিসাবে বিভ্রান্তিকর।
বিল করুন

15

একটি স্যুইচ বিবৃতিতে কেস স্টেটমেন্টগুলি কেবল লেবেল are

আপনি যখন কোনও মান স্যুইচ করেন, স্যুইচ বিবৃতিটি মিলবে মূল্যের সাথে লেবেলে মূলত একটি গোটো

এর মানে হল যে পরবর্তী লেবেলের অধীনে কোডটি দিয়ে যাওয়া এড়াতে ব্রেকটি প্রয়োজনীয়।

যে কারণে এটি এভাবে প্রয়োগ করা হয়েছিল - কোনও স্যুইচ স্টেটমেন্টের পতনের মধ্য দিয়ে প্রকৃতি কিছু পরিস্থিতিতে কার্যকর হতে পারে। উদাহরণ স্বরূপ:

case optionA:
    // optionA needs to do its own thing, and also B's thing.
    // Fall-through to optionB afterwards.
    // Its behaviour is a superset of B's.
case optionB:
    // optionB needs to do its own thing
    // Its behaviour is a subset of A's.
    break;
case optionC:
    // optionC is quite independent so it does its own thing.
    break;

2
দুটি বড় সমস্যা রয়েছে: 1) এটি breakযেখানে দরকার তা ভুলে যাওয়া । 2) যদি কেস স্টেটমেন্টগুলি তাদের অর্ডার পরিবর্তন করে থাকে, পতনের ফলে ভুল মামলা পরিচালিত হতে পারে। সুতরাং, আমি সি # এর হ্যান্ডলিংটি আরও ভাল দেখতে পেয়েছি ( goto caseখালি কেস লেবেল ব্যতীত পতনের জন্য স্পষ্ট )।
ড্যানিয়েল রোজ

@ ড্যানিয়েলরোজ: ১) breakসি # তেও ভুলে যাওয়ার উপায় রয়েছে - সর্বাধিক সহজটি হ'ল আপনি যখন কিছু করতে চান না caseতবে একটি যুক্ত করতে ভুলে যান break(সম্ভবত আপনি ব্যাখ্যামূলক মন্তব্যে আবৃত হয়ে গেছেন, বা কিছু সম্পর্কে ডেকেছেন) অন্যান্য টাস্ক): মৃত্যুদন্ড কার্যকর হবে কেবল caseনীচের দিকে। 2) উত্সাহিত goto caseকরা অব্যবহৃত "স্প্যাগেটি" কোডিংকে উত্সাহিত করছে - আপনি দুর্ঘটনাক্রান্ত চক্র ( case A: ... goto case B; case B: ... ; goto case A;) দিয়ে শেষ করতে পারেন , বিশেষত যখন ফাইলগুলি কেসগুলিতে পৃথক করা হয় এবং সংমিশ্রণে আঁকানো শক্ত হয়। সি ++ এ, পতনের মাধ্যমে স্থানীয়করণ করা হয়।
টনি ডেলরয়

8

যেমন জিনিস অনুমতি দিতে:

switch(foo) {
case 1:
    /* stuff for case 1 only */
    if (0) {
case 2:
    /* stuff for case 2 only */
    }
    /* stuff for cases 1 and 2 */
case 3:
    /* stuff for cases 1, 2, and 3 */
}

caseকীওয়ার্ডটিকে একটি gotoলেবেল হিসাবে ভাবুন এবং এটি অনেক প্রাকৃতিকভাবে আসে।


8
যে if(0)প্রথম ক্ষেত্রে শেষে মন্দ, এবং শুধুমাত্র যদি উদ্দেশ্য কোড অস্পষ্ট হয় ব্যবহার করা উচিত।
ড্যানিয়েল রোজ

11
এই পুরো উত্তরটি মন্দ হওয়ার মহড়া ছিল, আমার ধারণা think :-)
আর .. গিটহাব বন্ধ করুন ICE

3

এটি বেশিরভাগ ক্ষেত্রে একই কোড (বা একই কোড অনুসারে একই কোড) কার্যকর করতে হবে তখন কোড নকলকে সরিয়ে দেয়।

যেহেতু অ্যাসেম্বলি ভাষা স্তরের ক্ষেত্রে আপনি একে অপরের মধ্যে ভেঙে পড়েছেন বা যে কোনওভাবেই পড়ে যাওয়ার জন্য শূন্য ওভারহেড রয়েছে কিনা তা বিবেচ্য নয়, তবে কেন তারা কিছু ক্ষেত্রে উল্লেখযোগ্য সুবিধা দেওয়ার কারণে তাদের অনুমতি দেবেন না।


2

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

switch (nShorts)
{
case 4: frame.leadV1    = shortArray[3];
case 3: frame.leadIII   = shortArray[2];
case 2: frame.leadII    = shortArray[1];
case 1: frame.leadI     = shortArray[0]; break;
default: TS_ASSERT(false);
}

0

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

যদি আপনার পতনের মাধ্যমে কেস প্রতি কোডের একটি ব্লক থাকে, সম্ভবত আপনার যদি একটি if-elseif-else ব্লক ব্যবহার করা উচিত, কারণ এটি আরও উপযুক্ত বলে মনে হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.