স্যুইচ-কেসে বৈধ, তবে মূল্যহীন সিনট্যাক্স?


207

একটু টাইপের মাধ্যমে আমি দুর্ঘটনাক্রমে এই নির্মাণটি পেয়েছি:

int main(void) {
    char foo = 'c';

    switch(foo)
    {
        printf("Cant Touch This\n");   // This line is Unreachable

        case 'a': printf("A\n"); break;
        case 'b': printf("B\n"); break;
        case 'c': printf("C\n"); break;
        case 'd': printf("D\n"); break;
    }

    return 0;
}

দেখে মনে হয় যে বিবৃতিটির printfশীর্ষে switchবৈধ, তবে সম্পূর্ণ অ্যাক্সেসযোগ্য।

অ্যাক্সেসযোগ্য কোড সম্পর্কে সতর্কতা ছাড়াই আমি একটি পরিষ্কার সংকলন পেয়েছি, তবে এটি অর্থহীন বলে মনে হচ্ছে।

কোনও সংকলক কি এটিকে নাগম্য কোড হিসাবে পতাকাঙ্কিত করবে?
এটি কি আদৌ কোনও উদ্দেশ্য করে?


51
এর জন্য জিসিসির একটি বিশেষ পতাকা রয়েছে। এটি-Wswitch-unreachable
এলি সাদোফ

57
"এটি কি আদৌ কোনও উদ্দেশ্য করে?" ঠিক আছে, আপনি gotoঅন্যথায় অ্যাক্সেসযোগ্য অংশটি বাইরে চলে যেতে পারেন, যা বিভিন্ন হ্যাকের জন্য কার্যকর হতে পারে।
হলিব্ল্যাকট্যাগ

12
@ হোলিব্ল্যাকগ্যাট সব অ্যাক্সেসযোগ্য কোডের জন্য কি এমন হবে না?
এলি সাদোফ

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

16
ওয়ার্থ যে ইশারা @MooingDuck গুলি উদাহরণস্বরূপ ডাফের এর ডিভাইস (চালু একটি বৈকল্পিক হয় en.wikipedia.org/wiki/Duff's_device )
মাইকেল অ্যান্ডারসন

উত্তর:


226

সম্ভবত সবচেয়ে দরকারী না, তবে সম্পূর্ণ অকেজো নয়। switchস্কোপের মধ্যে উপলব্ধ একটি স্থানীয় ভেরিয়েবল ঘোষণা করতে আপনি এটি ব্যবহার করতে পারেন ।

switch (foo)
{
    int i;
case 0:
    i = 0;
    //....
case 1:
    i = 1;
    //....
}

স্ট্যান্ডার্ড ( N1579 6.8.4.2/7) এ নিম্নলিখিত নমুনা রয়েছে:

উদাহরণ কৃত্রিম প্রোগ্রাম খণ্ডে

switch (expr)
{
    int i = 4;
    f(i);
case 0:
    i = 17;
    /* falls through into default code */
default:
    printf("%d\n", i);
}

যার আইডেন্টিফায়ারটি iস্বয়ংক্রিয় স্টোরেজ সময়কাল (ব্লকের মধ্যে) এর সাথে উপস্থিত রয়েছে তবে কখনও তা আরম্ভ করা হয় না এবং এইভাবে যদি নিয়ন্ত্রণকারী এক্সপ্রেশনটির একটি ননজারো মান থাকে তবে printfফাংশনে কলটি একটি অনির্দিষ্ট মান অ্যাক্সেস করবে। একইভাবে, ফাংশনে কল fপৌঁছানো যায় না।

পিএস বিটিডাব্লু, নমুনাটি বৈধ সি ++ কোড নয়। N4140 6.7/3সেক্ষেত্রে ( , জোর দেওয়া আমার):

এমন একটি প্রোগ্রাম যা ৯০ টি বিন্দু থেকে লাফ দেয় যেখানে স্বয়ংক্রিয় স্টোরেজ সময়কালের সাথে একটি ভেরিয়েবল এমন বিন্দুতে অবধি থাকে না যেখানে এটি স্কোপে থাকে না যদি ভেরিয়েবলের স্কেলার টাইপ না হয় , তুচ্ছ ডিফল্ট কনস্ট্রাক্টর সহ শ্রেণীর ধরণ এবং তুচ্ছ ডেস্ট্রাক্টর, এর মধ্যে একটির সিভি-কোয়ালিটিড সংস্করণ, বা পূর্ববর্তী ধরণেরগুলির একটি অ্যারে এবং ইনিশিয়ালাইজার (8.5) ছাড়াই ঘোষণা করা হয়


90) একটি switchবিবৃতি শর্ত থেকে কেস লেবেল এ স্থানান্তর এই ক্ষেত্রে লাফিয়ে বিবেচনা করা হয়।

প্রতিস্থাপন তাই int i = 4;সঙ্গে int i;করে তোলে একটি বৈধ সি ++।


3
"... তবে কখনই আরম্ভ হয় না ..." দেখে মনে হচ্ছে i4 থেকে আরম্ভ করা হচ্ছে , আমি কী মিস করছি?
ইয়ানো

7
নোট করুন যে ভেরিয়েবলটি যদি হয় তবে staticএটি শূন্যে শুরু করা হবে, সুতরাং এর জন্যও নিরাপদ ব্যবহার রয়েছে।
লুশেনকো

23
@ অায়ানো আমরা সর্বদা সূচনাতে লাফাই i = 4;, তাই এটি কখনই ঘটে না।
অ্যালেক্সডি

12
হাহ! ... প্রশ্নের পুরো পয়েন্ট ... গিজ। ইচ্ছা এই
বোকাতা

1
নিস! কখনও কখনও আমি ক এর ভিতরে একটি অস্থায়ী পরিবর্তনশীল প্রয়োজন case, এবং সর্বদা প্রতিটি মধ্যে বিভিন্ন নাম ব্যবহার caseবা সুইচ বাইরে এটি সংজ্ঞায়িত করতে হবে।
এসজুয়ান 76

98

এটি কি আদৌ কোনও উদ্দেশ্য করে?

হ্যাঁ. যদি কোনও বিবৃতি পরিবর্তে, আপনি প্রথম লেবেলের আগে একটি ঘোষণা রেখে দেন, এটি সঠিক ধারণা করতে পারে:

switch (a) {
  int i;
case 0:
  i = f(); g(); h(i);
  break;
case 1:
  i = g(); f(); h(i);
  break;
}

ঘোষণা এবং বিবৃতিগুলির নিয়মগুলি সাধারণভাবে ব্লকের জন্য ভাগ করা হয়, সুতরাং এটি একই নিয়ম যা এটি সেখানে বিবৃতিও মঞ্জুরি দেয়।


পাশাপাশি উল্লেখযোগ্যভাবে এটিও গুরুত্বপূর্ণ যে প্রথম বিবৃতিটি একটি লুপ কনস্ট্রাক্ট হলে লুপের শরীরে কেস লেবেল উপস্থিত হতে পারে:

switch (i) {
  for (;;) {
    f();
  case 1:
    g();
  case 2:
    if (h()) break;
  }
}

এটি লেখার আরও পাঠযোগ্য উপায় থাকলে দয়া করে এ জাতীয় কোডটি লিখবেন না তবে এটি পুরোপুরি বৈধ এবং f()কলটি পৌঁছনীয়।


@ ম্যাথিউ এম ডফের ডিভাইসে একটি লুপের ভিতরে কেস লেবেল রয়েছে তবে লুপের আগে কেস লেবেল দিয়ে শুরু হয়।

2
আমি নিশ্চিত নই যে আমার কোন আকর্ষণীয় উদাহরণের জন্য উত্সাহিত করা উচিত বা সত্যিকারের প্রোগ্রামে এটি লেখার সম্পূর্ণ উন্মাদনার জন্য উত্সাহিত করা উচিত :)। অতল গহ্বরে ডুবিয়ে এক টুকরো করে ফিরে আসার জন্য অভিনন্দন।
Liviu টি।

@ChemicalEngineer: কোড একটি লুপের অংশ হয়, তাহলে যেমন ডাফের এর ডিভাইস আছে, { /*code*/ switch(x) { } }ক্লিনার হতে পারে কিন্তু এটি হল ভুল
বেন ভয়েগট

39

এটি ডফের ডিভাইস নামে একটি বিখ্যাত ব্যবহার রয়েছে ।

int n = (count+3)/4;
switch (count % 4) {
  do {
    case 0: *to = *from++;
    case 3: *to = *from++;
    case 2: *to = *from++;
    case 1: *to = *from++;
  } while (--n > 0);
}

এখানে আমরা দ্বারা একটি বাফার প্রতি ইঙ্গিত কপি fromএকটি বাফার দ্বারা প্রতি ইঙ্গিত করতে to। আমরা countতথ্য উদাহরণ কপি ।

do{}while()বিবৃতি প্রথম সামনে শুরু হয় caseলেবেল, এবং caseলেবেল মধ্যে এমবেড করা হয় do{}while()

এটি do{}while()প্রায় 4 টির একটি ফ্যাক্টর দ্বারা লুপের শেষে অবস্থিত শর্তাধীন শাখাগুলির সংখ্যা হ্রাস করে (উদাহরণস্বরূপ; ধ্রুবকটি আপনি যে কোনও মানটি চান তেমন টুইট করতে পারেন)।

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

সাধারণভাবে, পরিবর্তনীয় ঘোষণাগুলি সেখানে ঘটতে পারে এবং প্রতিটি ক্ষেত্রে ব্যবহার করা যেতে পারে, তবে স্যুইচ শেষ হওয়ার পরে সুযোগের বাইরে চলে যান। (নোট করুন কোনও সূচনা এড়ানো হবে)

এছাড়াও, নিয়ন্ত্রণ প্রবাহ যা স্যুইচ-নির্দিষ্ট নয় আপনাকে উপরের চিত্রের মতো, বা একটি দিয়ে স্যুইচ ব্লকের সেই বিভাগে নিয়ে যেতে পারে goto


2
অবশ্যই, এটি এখনও প্রথম মামলার উপরের বিবৃতিগুলিকে অনুমতি না দিয়েই সম্ভব হবে, এর আদেশ হিসাবে do {এবং case 0:কোনও ব্যাপার না, উভয়ই প্রথম দিকে লাফের লক্ষ্য রাখে *to = *from++;
বেন ভোইগট

1
@ বেনভয়েগ আমি যুক্তি দিয়েছি যে এইটি রাখা do {আরও পাঠযোগ্য। হ্যাঁ, ডাফের ডিভাইসের পাঠযোগ্যতার বিষয়ে তর্ক করা নির্বোধ এবং অর্থহীন এবং সম্ভবত উন্মাদ হওয়ার সহজ উপায়।
তহবিল মনিকার লসুইট

1
@ কিপ্যায়েস টেক্সেস আপনার সি সিথামের কর্টিনগুলি সি তে পরীক্ষা করা উচিত । হয়তো বা না.
জোনাস শোফার

@ জোনাস শ্যাফার মজাদারভাবে, সি ++ ২০ কর্টিনগুলি আপনার জন্য যা করছে তা মূলত এটি।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

15

ধরে নিই যে আপনি লিনাক্সে জিসিসি ব্যবহার করছেন, আপনি যদি ৪.৪ বা তার আগের সংস্করণ ব্যবহার করেন তবে এটি আপনাকে একটি সতর্কতা দিত।

-উনরিচিয়েবল-কোড বিকল্পটি জিসিসি ৪.৪-এর পরে সরানো হয়েছে


সমস্যাটি প্রথম হাতে পেয়ে সর্বদা সহায়তা করে!
16tons

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

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

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

1
... কিছু কনফিগারেশন অন্যদের চেয়ে বৃহত্তর কোড কেন জেনেছে তা জানার জন্য [উদাহরণস্বরূপ কারণ একটি সংকলক একটি কনফিগারেশনে কিছু শর্তকে অসম্ভব হিসাবে বিবেচনা করতে পারে তবে অন্যটি নয়] তবে এর অর্থ এই নয় যে কোডটির সাথে কোনও "ভুল" রয়েছে যা এতে অনুকূলিত হতে পারে কিছু কনফিগারেশন সহ যে ফ্যাশন।
সুপারক্যাট

11

কেবল পরিবর্তনশীল ঘোষণার জন্য নয়, পাশাপাশি উন্নত জাম্পিংও। আপনি যদি স্প্যাগেটি কোডে প্রবণ না হন এবং তবেই আপনি এটি ভালভাবে ব্যবহার করতে পারেন।

int main()
{
    int i = 1;
    switch(i)
    {
        nocase:
        printf("no case\n");

        case 0: printf("0\n"); break;
        case 1: printf("1\n"); goto nocase;
    }
    return 0;
}

ছাপে

1
no case
0 /* Notice how "0" prints even though i = 1 */

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


আর এর মধ্যে পার্থক্য কি nocase:এবং default:?
i486

@ i486 যখন i=4এটি ট্রিগার না করে nocase
সানচকে দেলোয়ার

পছন্দ করেছেন
njzk2

হেক কেন কেস 0 এর আগে কেবল 1 কেস রাখার পরিবর্তে এবং ফলথ্রু ব্যবহার করার কারণে এটি করবে?
জোনাস শোফার

@ জোনাস উইলিকি এই লক্ষ্যে আপনি এটি করতে পারতেন। তবে এই কোডটি কী করা যায় তার একটি প্রদর্শন ক্ষেত্রে।
সাঁচকে দেলোয়ার

11

এটি লক্ষ করা উচিত, যে switchবিবৃতিতে কোডটি বা case *:এই কোডের মধ্যে লেবেলগুলি রাখা হয়েছে সেখানে কার্যত কোনও কাঠামোগত বিধিনিষেধ নেই । এটি ডফের ডিভাইসের মতো প্রোগ্রামিং ট্রিকসকে সম্ভব করে তোলে , এর একটি সম্ভাব্য বাস্তবায়ন যা এর মতো দেখায়:

int n = ...;
int iterations = n/8;
switch(n%8) {
    while(iterations--) {
        sum += *ptr++;
        case 7: sum += *ptr++;
        case 6: sum += *ptr++;
        case 5: sum += *ptr++;
        case 4: sum += *ptr++;
        case 3: sum += *ptr++;
        case 2: sum += *ptr++;
        case 1: sum += *ptr++;
        case 0: ;
    }
}

আপনি দেখতে পাচ্ছেন যে, switch(n%8) {এবং case 7:লেবেলের মধ্যে কোড অবশ্যই পৌঁছবে ...


* সুপারক্যাট যেমন কৃতজ্ঞতার সাথে একটি মন্তব্যে উল্লেখ করেছেন : C99 সাল থেকে, কোনও ভিএলএর ঘোষণা রয়েছে এমন কোনও ঘোষণার সুযোগের মধ্যে একটি বা gotoলেবেল (তা case *:লেবেলই হোক বা নাও) উপস্থিত হতে পারে may সুতরাং এটি বলা ঠিক হবে না যে লেবেল স্থাপনের ক্ষেত্রে কোনও কাঠামোগত বাধা নেইcase *: । যাইহোক, ডফের ডিভাইসটি C99 স্ট্যান্ডার্ডের পূর্বাভাস দেয় এবং এটি কোনওভাবেই ভিএলএর উপর নির্ভর করে না। তবুও, আমি এই কারণে আমার প্রথম বাক্যে একটি "ভার্চুয়াল" সন্নিবেশ করতে বাধ্য হয়েছিল।


পরিবর্তনশীল দৈর্ঘ্যের অ্যারেগুলি যুক্ত হওয়ার কারণে তাদের সাথে সম্পর্কিত কাঠামোগত বিধিনিষেধ আরোপ করা হয়েছিল।
সুপারক্যাট

@ সুপের্যাট কি ধরণের বিধিনিষেধ?
মাস্টার -

1
কোনও ভেরিয়েবল-ঘোষিত অবজেক্ট বা প্রকারের স্কোপের মধ্যে একটি gotoবা switch/case/defaultলেবেল উভয়ই উপস্থিত হতে পারে। এর কার্যকরভাবে অর্থ হ'ল যদি কোনও ব্লকে পরিবর্তনশীল-দৈর্ঘ্য-অ্যারে অবজেক্ট বা প্রকারের কোনও ঘোষণা থাকে তবে যে কোনও লেবেল অবশ্যই সেই ঘোষণার আগে থাকতে পারে। স্ট্যান্ডার্ডে একটি বিভ্রান্তিকর ভার্চিয়া আছে যা সুপারিশ করবে যে কোনও কোনও ক্ষেত্রে ভিএলএ ঘোষণার সুযোগটি একটি সুইচ স্টেটমেন্টের সম্পূর্ণতা পর্যন্ত প্রসারিত; সে সম্পর্কে আমার প্রশ্নের জন্য stackoverflow.com/questions/41752072/… দেখুন ।
সুপারক্যাট

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

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

10

সতর্কতা উত্পন্ন করার জন্য প্রয়োজনীয় gccবিকল্পের সাথে আপনার উত্তরটি পেয়েছেন -Wswitch-unreachable, এই উত্তরটি ব্যবহারযোগ্যতা / যোগ্যতার অংশটি বিশদভাবে বর্ণনা করতে হবে ।

সরাসরি C11অধ্যায় §6.8.4.2, ( জোর আমার ) উদ্ধৃত করা হচ্ছে

switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}

যার আইডেন্টিফায়ারটি iস্বয়ংক্রিয় স্টোরেজ সময়কাল (ব্লকের মধ্যে) এর সাথে উপস্থিত রয়েছে তবে কখনও তা আরম্ভ করা হয় না এবং এইভাবে যদি নিয়ন্ত্রণকারী এক্সপ্রেশনটির একটি ননজারো মান থাকে তবে printf ফাংশনে কলটি একটি অনির্দিষ্ট মান অ্যাক্সেস করবে। একইভাবে, ফাংশনে কল fপৌঁছানো যায় না।

যা অত্যন্ত স্ব-বর্ণনামূলক। আপনি এটি স্থানীয়ভাবে স্কোপযুক্ত ভেরিয়েবল সংজ্ঞায়িত করতে ব্যবহার করতে পারেন যা কেবলমাত্র switchবিবৃতি সুযোগের মধ্যেই পাওয়া যায় ।


9

এটির সাথে "লুপ এবং অর্ধ" প্রয়োগ করা সম্ভব, যদিও এটি করার সর্বোত্তম উপায় এটি নাও হতে পারে:

char password[100];
switch(0) do
{
  printf("Invalid password, try again.\n");
default:
  read_password(password, sizeof(password));
} while (!is_valid_password(password));

@ রিচার্ডআইআই এটি একটি পাং বা কি? দয়া করে ব্যাখ্যা করুন.
ড্যান্সিয়া

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