স্যুইচ স্টেটমেন্টে ভেরিয়েবল কেন ঘোষণা করা যায় না?


944

আমি সর্বদা এটি ভাবছি - আপনি স্যুইচ স্টেটমেন্টে কেস লেবেলের পরে কেন ভেরিয়েবল ঘোষণা করতে পারবেন না? সি ++ তে আপনি ভেরিয়েবলগুলি বেশ কয়েকটি জায়গায় ঘোষণা করতে পারেন (এবং এগুলিকে প্রথম ব্যবহারের কাছাকাছি ঘোষণা করা অবশ্যই একটি ভাল জিনিস) তবে নিম্নলিখিতটি এখনও কার্যকর হবে না:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

উপরেরটি আমাকে নিম্নলিখিত ত্রুটি দেয় (এমএসসি):

'নিউওয়াল' এর সূচনাটি 'কেস' লেবেল দ্বারা এড়ানো যায়

এটি অন্যান্য ভাষায়ও সীমাবদ্ধ বলে মনে হয়। কেন এমন সমস্যা হচ্ছে?


10
একটি ব্যাখ্যা সি বিএনএফ ব্যাকরণ উপর ভিত্তি করে জন্য, দেখুন stackoverflow.com/questions/1180550/weird-switch-error-in-obj-c/...
johne

এখানে স্যুইচ স্টেটমেন্ট এবং লেবেল (এবিসি :) সাধারণভাবে খুব ভাল পঠিত
ইথেরিয়লোনে

4
আমি বলব যে 'ঘোষণার পরিবর্তে স্যুইচ স্টেটমেন্টে কেন ভেরিয়েবলগুলি আরম্ভ করা যায় না' ince ভেরিয়েবলটি ঘোষণা করে কেবল এমএসভিসিতে আমাকে কেবল একটি সতর্কতা দিন।
জুমআইন

উত্তর:


1141

Caseবিবৃতি শুধুমাত্র লেবেল । এর অর্থ সংকলক সরাসরি লেবেলে লাফিয়ে লাফিয়ে এইরূপ ব্যাখ্যা করবে। সি ++ এ, এখানে সমস্যাটি সুযোগের একটি। আপনার কোঁকড়া বন্ধনী switchস্টেটমেন্টের ভিতরে সমস্ত কিছু হিসাবে স্কোপটিকে সংজ্ঞা দেয় । এর অর্থ হ'ল আপনি এমন একটি সুযোগ রেখে গেছেন যেখানে আরম্ভের স্কিপিং কোডে আরও একটি লাফ করা হবে।

এটি পরিচালনা করার সঠিক উপায়টি হ'ল caseউক্তির সাথে সম্পর্কিত একটি ক্ষেত্রকে সংজ্ঞায়িত করা এবং এর মধ্যে আপনার ভেরিয়েবল সংজ্ঞা দেওয়া:

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}

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

10
আমি জেফের সাথে একমত - বেশিরভাগ লোকেরা ইনডেন্টিং স্টাইলের কারণে স্যুইচ স্টেটমেন্টটি পড়ার সময় সুযোগটি "ধরে নেওয়া" এত সহজ all আমার নিজস্ব স্টাইলটি প্রতিটি ক্ষেত্রে / ডিফল্টের জন্য এক লাইনের বেশি দীর্ঘ হলে সর্বদা একটি নতুন সুযোগ খোলা থাকে।
বিড

39
workmad3 - আপনি যদি কোনও নতুন ভেরিয়েবল ঘোষণা না করেন তবে আপনি আমাকে এমন কোনও সি ++ সংকলক খুঁজে পেতে পারেন যা একটি নতুন স্ট্যাক ফ্রেম তৈরি করবে? আপনি আমাকে সংক্ষেপে চিন্তিত করেছিলেন, তবে জি ++ 3.1, ভিজ্যুয়াল সি ++ 7 বা ইন্টেল সি ++ 8 এর কোনওটিই নতুন স্কোপের জন্য এমন কোনও কোড তৈরি করবে না যেখানে আপনি কোনও ভেরিয়েবল ঘোষণা করেন না।
ক্রিস জেফারসন

10
@ workmad3 একটি নতুন কোঁকড়া ধনুর্বন্ধনী ব্লক লিখে একটি নতুন স্ট্যাক ফ্রেম ক্ষতিসাধন করে না stackoverflow.com/questions/2759371/...
MTVS

3
@ টালজেফ আমি জানি না যে 'পুরানো দিনগুলি' আপনি কী উল্লেখ করছেন। 40 বছরের মধ্যে, পদ্ধতিটি প্রবেশ করার সময় কোনও পদ্ধতির জন্য সমস্ত স্ট্যাকের স্থান বরাদ্দ না হওয়াতে আমি কোনও সংকলকের মুখোমুখি হই নি ।
ব্যবহারকারী 207421

331

এই প্রশ্নের করা হয় মূলত [সি] এবং [সি ++] একই সময়ে যেমন ট্যাগ করা হয়েছে। মূল কোডটি অবশ্যই সি এবং সি উভয় ক্ষেত্রেই অবৈধ, তবে সম্পূর্ণ ভিন্ন সম্পর্কযুক্ত কারণে।

  • সি ++ এ এই কোডটি অবৈধ কারণ case ANOTHER_VAL:লেবেলটি newValতার শুরুটি বাইপাস করে ভেরিয়েবলের স্কোপে যায় । স্বয়ংক্রিয় অবজেক্টগুলির সূচনা বাইপাস করা সিঁধে সি ++ অবৈধ। ইস্যুটির এই দিকটি বেশিরভাগ উত্তর দ্বারা সঠিকভাবে সম্বোধন করা হয়।

  • তবে সি ভাষায় ভেরিয়েবল ইনিশিয়ালাইজেশন বাইপাস করা কোনও ত্রুটি নয়। এর সূচনাকরণের উপরে কোনও ভেরিয়েবলের স্কোপে জাম্পিং আইনী আইন সি। এর সহজভাবে এর অর্থ হ'ল ভেরিয়েবলটি অবিচ্ছিন্ন রেখে দেওয়া হয়েছে। আসল কোডটি সম্পূর্ণ ভিন্ন কারণে সিতে সংকলন করে না। লেবেল case VAL:মূল কোডে পরিবর্তনশীল ঘোষণা সংযুক্ত newVal। সি ভাষায় ঘোষণাগুলি বিবৃতি নয়। তাদের লেবেল দেওয়া যায় না। এই কোডটি সি কোড হিসাবে ব্যাখ্যা করা হলে ত্রুটির কারণ হয়।

    switch (val)  
    {  
    case VAL:             /* <- C error is here */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:     /* <- C++ error is here */
      ...
      break;
    }

একটি অতিরিক্ত {}ব্লক যুক্ত করা সি ++ এবং সি উভয় সমস্যার সমাধান করে, যদিও এই সমস্যাগুলি খুব আলাদা হয়ে থাকে। সি ++ এর দিক থেকে এটি এর পরিসরকে সীমাবদ্ধ করে, এটি newValনিশ্চিত করে যে case ANOTHER_VAL:এই সুযোগে আর লাফ না পড়ে, যা সি ++ ইস্যুটি সরিয়ে দেয়। সি এর পাশে অতিরিক্ত {}একটি যৌগিক বিবৃতি প্রবর্তন করে, এইভাবে case VAL:একটি বিবৃতিতে প্রয়োগ করার জন্য লেবেল তৈরি করে , যা সি ইস্যুটিকে মুছে ফেলে।

  • সি ক্ষেত্রে সমস্যাটি সহজেই সমাধান করা যেতে পারে {}case VAL:লেবেলের পরে কেবল একটি খালি বিবৃতি যুক্ত করুন এবং কোডটি বৈধ হয়ে উঠবে

    switch (val)  
    {  
    case VAL:;            /* Now it works in C! */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:  
      ...
      break;
    }

    মনে রাখবেন যে এটি এখন সি দৃষ্টিকোণ থেকে বৈধ হলেও এটি সি ++ দৃষ্টিকোণ থেকে অবৈধ remains

  • প্রতিসমভাবে, সি ++ ক্ষেত্রে সমস্যাটি সহজেই সমাধান করা যেতে পারে {}। ভেরিয়েবল ডিক্লেয়ারেশন থেকে আরম্ভকারীটিকে সরিয়ে দিন এবং কোডটি বৈধ হয়ে উঠবে

    switch (val)  
    {  
    case VAL: 
      int newVal;
      newVal = 42;  
      break;
    case ANOTHER_VAL:     /* Now it works in C++! */
      ...
      break;
    }

    মনে রাখবেন যে এটি এখন সি ++ দৃষ্টিকোণ থেকে বৈধ হলেও এটি সি দৃষ্টিকোণ থেকে অবৈধ remains


4
@ অ্যান্ট: আমি বুঝতে পারি যে সি ++ স্থির করে এমন একটি কেন সিটির জন্য প্রযোজ্য নয়; যাইহোক, আমি বুঝতে সক্ষম হই না যে এটি প্রথম স্থানে ইনিশিয়ালেশনটি এড়িয়ে যাওয়ার সি ++ ইস্যুটি কীভাবে ঠিক করে? এটি এখনও ঘোষণা এবং নিয়োগ লাফালাফি করবে না newValযখন এটি জাম্প ANOTHER_VAL?
কিংবদন্তি 2 কে

13
@ কিংবদন্তি 2 কে: হ্যাঁ, এটি এখনও এড়িয়ে যায়। যাইহোক, যখন আমি বলতে "এটি ইস্যু সমাধান করা হয়েছে", আমি বলতে চাচ্ছি যে এটি সংশোধন করা হয়েছে সি ++ কম্পাইলার এরর । সি ++ তে প্রাথমিককরণ দিয়ে স্কেলার ঘোষণাকে এড়ানো অবৈধ , তবে ইনিশিয়ালাইজার ছাড়াই স্কেলারের ঘোষণা বাদ দেওয়া পুরোপুরি ঠিক । এ case ANOTHER_VAL:বিন্দু পরিবর্তনশীল newValদৃশ্যমান থাকবে তবে অনির্দিষ্ট মান।
এএনটি

3
আকর্ষনীয়। §A9.3: Compound Statementকেএন্ডআর সি (দ্বিতীয় সংস্করণ) থেকে পড়ার পরে আমি এই প্রশ্নটি পেয়েছি । এন্ট্রিটিতে একটি যৌগিক বিবৃতি সম্পর্কিত প্রযুক্তিগত সংজ্ঞা উল্লেখ করা হয়েছে {declaration-list[opt] statement-list[opt]}। বিভ্রান্ত, কারণ আমি একটি ঘোষণাপত্রটি একটি বিবৃতি ছিল বলে ভেবেছিলাম, তাই আমি এটি সন্ধান করেছি এবং সঙ্গে সঙ্গে এই প্রশ্নটি খুঁজে পেয়েছি, যেখানে একটি উদাহরণ বলেছে যে বৈষম্য প্রকট হয়ে যায় এবং আসলে একটি প্রোগ্রামকে ভেঙে দেয় । আমি বিশ্বাস করি যে আরও একটি সমাধান (সি এর জন্য) ঘোষণার আগে আরেকটি বিবৃতি (সম্ভবত নাল স্টেটমেন্ট?) রাখা উচিত যাতে লেবেলযুক্ত-বিবৃতিটি সন্তুষ্ট হয়।
ব্র্যাডেন সেরা

ওফস, আমি সবেমাত্র লক্ষ্য করেছি যে আমি নাল-বিবৃতি সমাধানটি প্রস্তাব করেছি তা ইতিমধ্যে আপনার উত্তরে রয়েছে। তাহলে কখনো কিছু মনে করো না.
ব্র্যাডেন সেরা

3
এটি লক্ষণীয় যে খালি বিবৃতি যোগ করার ফিক্সটি কেবল C99 এর পরে কাজ করে। C89-এ, ভেরিয়েবলগুলি অবশ্যই তাদের এনক্লোজিং ব্লকের শুরুতে ঘোষণা করতে হবে।
আর্থার ট্যাকা

136

ঠিক আছে. কেবল এটিকে স্পষ্ট করে বলতে গেলে এই ঘোষণার সাথে কোনও সম্পর্ক নেই। এটি কেবলমাত্র "আরম্ভের উপরে ঝাঁপিয়ে পড়া" (আইএসও সি ++ '03 6.7 / 3) এর সাথে সম্পর্কিত

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

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

যেখানে অবজেক্টটি একটি নন-পিওডি বা সংকলক সংহত করে স্পষ্টভাবে একটি আরম্ভকারীকে যুক্ত করে, এবং সুতরাং এই জাতীয় ঘোষণার উপরে ঝাঁপ দেওয়া সম্ভব নয়:

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

এই সীমাবদ্ধতাটি স্যুইচ বিবৃতিতে সীমাবদ্ধ নয়। শুরুতে ঝাঁপিয়ে পড়ার জন্য 'গোটো' ব্যবহার করাও ত্রুটি:

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

কিছুটা ট্রিভিয়া হ'ল এটি সি ++ এবং সি এর মধ্যে একটি পার্থক্য, এটি আরম্ভের দিকে ঝাঁপিয়ে দেওয়া ত্রুটি নয়।

অন্যরা যেমন উল্লেখ করেছেন, সমাধানটি হল একটি নেস্টেড ব্লক যুক্ত করা যাতে ভেরিয়েবলের আজীবন পৃথক কেস লেবেলে সীমাবদ্ধ থাকে।


2
"প্রারম্ভিককরণের ওপরে ত্রুটি লাফিয়ে উঠছে" ??? আমার জিসিসির সাথে নেই। লেবেলের নীচে জে ব্যবহার করার সময় এটি "জে একত্রীকরণযোগ্য হতে পারে" সতর্কতা দিতে পারে, তবে কোনও ত্রুটি নেই। তবে, স্যুইচের ক্ষেত্রে একটি ত্রুটি রয়েছে (একটি হার্ড ত্রুটি, দুর্বল সতর্কতা নয়)।
মেকি

9
@ মেককি: এটি সি ++ তে অবৈধ। আইএসও সি ++ '03 - 7.7 / ৩: "... এমন একটি প্রোগ্রাম যা স্বয়ংক্রিয় স্টোরেজ সময়কাল সহ স্থানীয় ভেরিয়েবল এমন একটি বিন্দুতে স্কোপ না করে যেখানে একটি ক্ষেত্রের মধ্যে অবস্থান করে, যদি না ভেরিয়েবলের POD টাইপ থাকে (3.9) এবং ইনিশিয়ালাইজার (8.5) ছাড়াই ঘোষণা করা হয়। "
রিচার্ড কর্ডেন

1
হ্যাঁ, তবে এটি সি তে অবৈধ নয় (কমপক্ষে জিসিসি এটি বলে না)। j টি অবিচ্ছিন্ন করা হবে (কিছু এলোমেলো সংখ্যা আছে), তবে সংকলক এটি সংকলন করে। তবে, স্যুইচ স্টেটমেন্টের ক্ষেত্রে, সংকলকটি এটি সংকলন করবে না এবং আমি একটি গোটো / লেবেল কেস এবং একটি সুইচ কেসের মধ্যে পার্থক্য দেখতে ব্যর্থ।
মেকি

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

38

পুরো সুইচ স্টেটমেন্ট একই সুযোগে আছে। এটির কাছাকাছি যেতে, এটি করুন:

switch (val)
{
    case VAL:
    {
        // This **will** work
        int newVal = 42;
    }
    break;

    case ANOTHER_VAL:
      ...
    break;
}

বন্ধনী নোট করুন।


30

সমস্ত উত্তর এবং আরও কিছু গবেষণা পড়ার পরে আমি কয়েকটি জিনিস পাই।

Case statements are only 'labels'

সি তে, স্পেসিফিকেশন অনুযায়ী,

.86.8.1 লেবেলযুক্ত বিবৃতি:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

সি তে এমন কোনও ধারা নেই যা "লেবেলযুক্ত ঘোষণার" জন্য অনুমতি দেয়। এটি কেবল ভাষার অংশ নয়।

সুতরাং

case 1: int x=10;
        printf(" x is %d",x);
break;

এটি সংকলন করবে না , দেখুন http://codepad.org/YiyLQTYw । জিসিসি একটি ত্রুটি দিচ্ছে:

label can only be a part of statement and declaration is not a statement

এমন কি

  case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;

এই হয় এছাড়াও সংকলন না দেখতে http://codepad.org/BXnRD3bu । এখানেও আমি একই ত্রুটি পাচ্ছি।


সি ++ এ, স্পেসিফিকেশন অনুযায়ী,

লেবেল-ঘোষণার অনুমতি থাকলেও লেবেলযুক্ত-অস্বীকৃতি অনুমোদিত নয়।

Http://codepad.org/ZmQ0IyDG দেখুন ।


এ জাতীয় অবস্থার সমাধান দুটি

  1. হয় scope using ব্যবহার করে নতুন স্কোপ ব্যবহার করুন

    case 1:
           {
               int x=10;
               printf(" x is %d", x);
           }
    break;
  2. অথবা লেবেলযুক্ত ডামি স্টেটমেন্ট ব্যবহার করুন

    case 1: ;
               int x=10;
               printf(" x is %d",x);
    break;
  3. স্যুইচ () এর আগে ভেরিয়েবলটি ঘোষণা করুন এবং যদি এটি আপনার প্রয়োজনীয়তা পূরণ করে তবে কেস স্টেটমেন্টে এটি বিভিন্ন মান দিয়ে শুরু করুন

    main()
    {
        int x;   // Declare before
        switch(a)
        {
        case 1: x=10;
            break;
    
        case 2: x=20;
            break;
        }
    }

সুইচ স্টেটমেন্ট সহ আরও কিছু জিনিস

স্যুইচে কোনও বিবৃতি কখনও লিখবেন না যা কোনও লেবেলের অংশ নয়, কারণ সেগুলি কখনও কার্যকর করা হবে না:

switch(a)
{
    printf("This will never print"); // This will never executed

    case 1:
        printf(" 1");
        break;

    default:
        break;
}

Http://codepad.org/PA1quYX3 দেখুন ।


2
আপনি সি সমস্যাটি সঠিকভাবে বর্ণনা করেছেন। তবে সি ++ লেবেলযুক্ত আরম্ভের অনুমতি নেই বলে দেওয়া দৃ .়তা সম্পূর্ণ সত্য নয়। সি ++ তে লেবেলযুক্ত সূচনাতে কোনও সমস্যা নেই। কি সি ++ অনুমতি দেয় না হয় ধরে জাম্পিং ভেরিয়েবলের আরম্ভের aপরিবর্তনশীল এর সুযোগ মধ্যে a। সুতরাং, সি দৃষ্টিকোণ থেকে, সমস্যাগুলি case VAL:লেবেলযুক্ত এবং আপনি এটিকে সঠিকভাবে বর্ণনা করেছেন। তবে সি ++ দৃষ্টিকোণ থেকে সমস্যাটি case ANOTHER_VAL:লেবেল নিয়ে।
এএনটি

সি ++ এ, সি-এর বিপরীতে, ঘোষণাগুলি বিবৃতিগুলির একটি উপসেট হয়।
কিথ থমসন

20

আপনি এটি করতে পারবেন না, কারণ caseলেবেলগুলি হ'ল ব্লকটিতে কেবলমাত্র প্রবেশের পয়েন্ট।

এটি ডফের ডিভাইস দ্বারা সর্বাধিক স্পষ্টভাবে চিত্রিত । উইকিপিডিয়া থেকে এখানে কিছু কোড রয়েছে:

strcpy(char *to, char *from, size_t 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);
    }
}

লক্ষ্য করুন কীভাবে caseলেবেলগুলি সম্পূর্ণরূপে ব্লকের সীমানা উপেক্ষা করে। হ্যাঁ, এটি মন্দ। তবে এই কারণেই আপনার কোড উদাহরণ কার্যকর হয় না। caseলেবেলে জাম্পিং করা ব্যবহারের সমান goto, সুতরাং আপনাকে কোনও কনস্ট্রাক্টরের সাথে স্থানীয় ভেরিয়েবলের উপরে ঝাঁপ দেওয়ার অনুমতি নেই।

অন্যান্য বেশ কয়েকটি পোস্টার ইঙ্গিত হিসাবে, আপনার নিজের একটি ব্লক লাগাতে হবে:

switch (...) {
    case FOO: {
        MyObject x(...);
        ...
        break; 
    }
    ...
 }

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

1
@ আর ..: কি ?! একটি দুটি পরিপূরক সিস্টেমে, স্বাক্ষর 2 এর ক্ষমতার দ্বারা মডুলোগুলিকে প্রভাবিত করে না (এটি কেবল নীচে বিটগুলির মধ্যে একটি) এবং যতক্ষণ না আপনার প্রসেসরের আর্কিটেকচারের গাণিতিক ডান-শিফট অপারেশন থাকে ততক্ষণ 2 এর দ্বারা বিভাজনগুলিকে প্রভাবিত করে না ( SARx86 এ, বনাম SHRযা স্বাক্ষরবিহীন শিফটের জন্য)।
ক্রিস জেস্টার-ইয়ং

@ ক্রিস: আমি বিশ্বাস করি যে তার অর্থ যখন সংকলককে অবশ্যই নেতিবাচক মানগুলির জন্য অনুমতি দিতে হবে যেখানে "নীচে বিটগুলির মধ্যে কেবল একটি অ্যান্ড" রাখা যায় না; উদাহরণস্বরূপ, -1% 8 জি ++ ব্যবহার করে এই দুটির পরিপূরক সিস্টেমে -1 দেয় (এই ক্ষেত্রে সাইন ইন 5.5 / 4 প্রতি প্রয়োগকরণের সংজ্ঞা দেওয়া হয়)।

3
@ ক্রিস: আমি আপনার সাথে একমত যে আর এর প্রভাবটি অতিরঞ্জিত করছে; আমি কেবল আপনার মন্তব্য দেখেছি এবং একটি সহজ এবং যথেষ্ট ছিল না জানি।

1
এছাড়াও লক্ষ্য করার মতো মূল উইকিপিডিয়া কোডটি মেমরি ম্যাপযুক্ত আউটপুটটিতে ডেটা প্রেরণের জন্য যা এখানে বিশিষ্ট দেখাচ্ছে কারণ এটি উল্লেখ করা হয়নি এবং প্রতিটি বাইট একই "টু" অবস্থানটিতে অনুলিপি করা হয়েছে। এটিতে পোস্টফিক্স ++ যুক্ত করে বা ব্যবহারের ক্ষেত্রে উল্লেখ করে মেমরি ম্যাপ করা আইও by মূল প্রশ্নের মূলত পেরিফেরিয়াল :-)।
পিটার

16

এখনও অবধি বেশিরভাগ উত্তর এক দিক থেকে ভুল: আপনি কেস স্টেটমেন্টের পরে ভেরিয়েবল ঘোষণা করতে পারেন , তবে আপনি সেগুলি আরম্ভ করতে পারবেন না :

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

পূর্বে উল্লিখিত হিসাবে, এর চারপাশের একটি দুর্দান্ত উপায় হ'ল আপনার মামলার সুযোগ তৈরি করার জন্য ধনুর্বন্ধনী ব্যবহার করা।


1
মিঃ 32 আপনি আপনার ত্রুটিটি কী তা ভুল বুঝতে পেরেছেন: হ্যাঁ এটি সংকলন করতে যাচ্ছে না তবে আপনি একটি স্যুইচের অভ্যন্তরে ভেরিয়েবল ঘোষণা করছেন বলে নয়। ত্রুটিটি হ'ল কারণ আপনি একটি বিবৃতি দেওয়ার পরে ভেরিয়েবল ঘোষণা করার চেষ্টা করছেন যা সি
তে

1
এখন এমন দিন যা সি 90 এ বৈধ এবং সি এর নতুন সংস্করণ
জিগার প্যাটেল

12

আমার প্রিয় অশুচি সুইচ কৌশলটি একটি অবাঞ্ছিত কেস লেবেল এড়াতে যদি একটি (0) ব্যবহার করে।

switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}

তবে খুব খারাপ।


খুব সুন্দর. উদাহরণস্বরূপ: কেস 0 এবং কেস 1 উদাহরণস্বরূপ
পরিবর্তিতভাবে পৃথকভাবে পরিবর্তিত

1
আপনি যদি চান তবে কেস 0 এবং কেস 1 উভয় ক্ষেত্রে 2 এর মধ্যে পড়তে হবে (কেস 0 কেস 1 এর মধ্যে পড়ে না)। এটি সত্যিই দরকারী কিনা তা জানেন না তবে নিশ্চিতভাবে কাজ করে।
পেট্রুজা

1
আপনি gotoকোডটি
অবলম্বন


7

আপনি যদি নতুন ব্লক শুরু করেন তবে আপনি স্যুইচ স্টেটমেন্টের মধ্যে ভেরিয়েবলগুলি ঘোষণা করতে পারেন :

switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}

স্থানীয় ভেরিয়েবল (গুলি) সঞ্চয় করার জন্য স্ট্যাকের স্থান বরাদ্দকরণ (এবং পুনরায় দাবি করা) এর কারণটি।


1
পরিবর্তনশীল ঘোষণা করা যেতে পারে, তবে এটি আরম্ভ করা যায় না। এছাড়াও, আমি নিশ্চিত যে বিষয়টি স্ট্যাক এবং স্থানীয় ভেরিয়েবলগুলির সাথে কোনওভাবেই সম্পর্কিত নয় pretty
রিচার্ড কর্ডেন

6

বিবেচনা:

switch(val)
{
case VAL:
   int newVal = 42;
default:
   int newVal = 23;
}

ব্রেক স্টেটমেন্টের অভাবে, কখনও কখনও নিউওয়াল দু'বার ঘোষিত হয় এবং আপনি জানেন না যে এটি রানটাইম পর্যন্ত হয় কিনা। আমার ধারণা সীমাবদ্ধতা কারণ এই ধরণের বিভ্রান্তি of নতুনওয়ালের সুযোগ কী হবে? কনভেনশন নির্দেশ করে যে এটি পুরো সুইচ ব্লক (ধনুর্বন্ধনীগুলির মধ্যে) হবে।

আমি কোনও সি ++ প্রোগ্রামার নই, তবে সি তে:

switch(val) {
    int x;
    case VAL:
        x=1;
}

ঠিকভাবে কাজ করে. একটি স্যুইচ ব্লকের ভিতরে ভেরিয়েবল ঘোষণা করা ভাল। কেস গার্ড পরে ঘোষণা করা হয় না।


3
@ মিঃ 32: প্রকৃতপক্ষে আপনার উদাহরণটি দেখায় যে একটি প্রিন্টফ এক্সিকিউট করা হয় নি, তবে এই ক্ষেত্রে, ইন্ট এক্সটি কোনও বিবৃতি নয় বরং একটি ঘোষণাপত্র, এক্স ঘোষিত হয়, প্রতিটি সময় ফাংশন পরিবেশ সজ্জিত হওয়ার জন্য এটির জন্য স্থান সংরক্ষণ করা হয়, দেখুন: codepad.org/4E9Zuz1e
পেট্রুজা

আমি প্রশ্নের শিরোনামটি পড়ার সময় এটির সন্ধানের প্রত্যাশা করছিলাম, কারণ প্রশ্নটি "কেস:" লেবেলের মধ্যে পরিবর্তনশীল ঘোষণার বিষয়ে নয়, তবে স্যুইচ স্টেটমেন্টগুলিতে। এবং কেবলমাত্র আপনি (এবং ভিক্টরএইচ, আপনার উত্তরটির উপর জোর দিয়ে) বাস্তবে স্যুইচ স্টেটমেন্টগুলিতে পরিবর্তনশীল সম্পর্কে কথা বলেছেন।
সিসেস

4

স্যুইচের পুরো বিভাগটি একক ঘোষণার প্রসঙ্গ। আপনি এর মতো কেস স্টেটমেন্টে ভেরিয়েবল ঘোষণা করতে পারবেন না। পরিবর্তে এটি চেষ্টা করুন:

switch (val)  
{  
case VAL:
{
  // This will work
  int newVal = 42;
  break;
}
case ANOTHER_VAL:  
  ...
  break;
}

পরিবর্তনশীল ঘোষণা করা যেতে পারে, তবে এটি আরম্ভ করা যায় না।
রিচার্ড কর্ডেন

@ রিচার্ড কর্ডেন আমি আত্মবিশ্বাসী যে প্রাথমিককরণ কার্যকর হবে। আপনি এখনও দৃsert়রূপে এটি আরম্ভ করা যাবে না?
চুকস - মনিকা পুনরায় ইনস্টল করুন

3

যদি আপনার কোডটি "ইনট নিউওয়াল = 42" বলে থাকে তবে আপনি যুক্তিসঙ্গতভাবে আশা করতে পারেন যে নিউভালটি কখনই অবিচ্ছিন্ন করা হবে না। তবে আপনি যদি এই বিবৃতিটি (যা আপনি যা করছেন) এর বাইরে চলে যান তবে ঠিক যা ঘটে তা ঘটে - নিউভাল ইন-স্কোপ হয় তবে তাকে বরাদ্দ করা হয়নি।

আপনি যদি সত্যই এটি ঘটতে চেয়েছিলেন তবে ভাষাটি "ইনট নিউওয়াল; নিউওয়াল = 42;" বলার মাধ্যমে এটি স্পষ্ট করে তুলতে হবে। অন্যথায় আপনি নিউওয়ালের সুযোগ একক ক্ষেত্রে সীমাবদ্ধ করতে পারেন, যা আপনি চেয়েছিলেন সম্ভবত।

যদি আপনি একই উদাহরণ বিবেচনা করেন তবে "কনট ইনট নিউওয়াল = 42;"


3

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

switch (val) {  
  /* This *will* work, even in C89 */
  int newVal = 42;  
case VAL:
  newVal = 1984; 
  break;
case ANOTHER_VAL:  
  newVal = 2001;
  break;
}

-1 এখানে int newVal = 42; কখনও মৃত্যুদন্ড কার্যকর করা হবে না। এই কোডেপ্যাড.অর্গ
পিএএএকওয়াইএক্স

4
ঘোষণাটি কার্যকর করা int newVal হবে , তবে = 42অ্যাসাইনমেন্টটি নয়।
পেট্রুজা

3

এখনও পর্যন্ত উত্তরগুলি সি ++ এর জন্য হয়েছে।

সি ++ এর জন্য, আপনি কোনও আরম্ভের উপরে ঝাঁপিয়ে উঠতে পারবেন না। আপনি সিতে পারেন তবে, সি তে, একটি ঘোষণা কোনও বিবৃতি নয়, এবং কেস লেবেলগুলি বিবৃতি অনুসরণ করতে হবে।

সুতরাং, বৈধ (তবে কুৎসিত) সি, অবৈধ সি ++

switch (something)
{
  case 1:; // Ugly hack empty statement
    int i = 6;
    do_stuff_with_i(i);
    break;
  case 2:
    do_something();
    break;
  default:
    get_a_life();
}

পরিবর্তে, সি ++ এ, ঘোষণা একটি বিবৃতি, সুতরাং নিম্নলিখিতটি বৈধ সি ++, অবৈধ সি

switch (something)
{
  case 1:
    do_something();
    break;
  case 2:
    int i = 12;
    do_something_else();
}

1
। দ্বিতীয় উদাহরণ বৈধ সি ++ (vc2010 এবং জিসিসি 4.6.1 সি ++ না আরম্ভের লাফালাফি করার অনুমতি দিয়ে পরীক্ষা নয় অংশ জিসিসি ত্রুটি বার্তাটি আছে: 'int- এ আমি' ক্রস আরম্ভের
zhaorufei

3

আকর্ষণীয় যে এটি ঠিক আছে:

switch (i)  
{  
case 0:  
    int j;  
    j = 7;  
    break;  

case 1:  
    break;
}

... তবে এটি নয়:

switch (i)  
{  
case 0:  
    int j = 7;  
    break;  

case 1:  
    break;
}

আমি পাই যে একটি ফিক্স যথেষ্ট সহজ, তবে আমি এখনও বুঝতে পারি না কেন প্রথম উদাহরণটি সংকলককে বিরক্ত করে না। যেমনটি আগে উল্লেখ করা হয়েছিল (২ বছর আগে হি), ঘোষণাটি তর্ক থাকা সত্ত্বেও ত্রুটি সৃষ্টি করে না। ইনিশিয়েশনই সমস্যা। যদি ভেরিয়েবলটি শুরু করে এবং বিভিন্ন লাইনে ঘোষিত হয় তবে এটি সংকলন করে।


1
প্রথমটি জিসিসি 4.2-তে সঠিক নয়: "ত্রুটি: 'ইনট' এর আগে প্রত্যাশিত এক্সপ্রেশন"। যেমন পিটার এবং মিস্টার 32 বলেছেন, "কেস 0:; ইন্ট জে; ..." এবং "কেস 0:; ইন্ট জে = 7; ..." উভয়ই কাজ করে। সি তে সমস্যাটি কেবলমাত্র "কেস <লেবেল>: ঘোষণা" বৈধ সি সিনট্যাক্স নয়।
সন্দেহভাজন

3

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

মূল প্রশ্নে:

int i;
i = 2;
switch(i)
{
    case 1: 
        int k;
        break;
    case 2:
        k = 1;
        cout<<k<<endl;
        break;
}

আসলে 2 টি প্রশ্ন আছে:

1. কেন আমি caseলেবেলের পরে একটি পরিবর্তনশীল ঘোষণা করতে পারি ?

এটি কারণ সি ++ লেবেল আকারে থাকতে হবে:

এন 3337 6.1 / 1

লেবেল করা-বিবৃতি:

...

  • বৈশিষ্ট্য-নির্দিষ্টকরণকারী-সিকোপ্ট case constant-expression :statement

...

আর এ C++ ঘোষণা বিবৃতি এছাড়াও হিসাবে বিবেচনা করা হয় বিবৃতি (যেমন বিরোধিতা C):

এন 3337 6/1:

বিবৃতি :

...

ঘোষণামূলক বিবৃতি

...

২. কেন আমি পরিবর্তনশীল ঘোষণার উপরে ঝাঁপিয়ে পড়তে পারি এবং তারপরে এটি ব্যবহার করতে পারি?

কারণ: N3337 6.7 / 3

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

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

যেহেতু kহল স্কেলার টাইপ , এবং ঘোষণা জাম্পিং সময়ে শুরু করা হয়নি ধরে ঘোষণার সম্ভব। এটি শব্দার্থগতভাবে সমতুল্য:

goto label;

int x;

label:
cout << x << endl;

তবে এটি সম্ভব হবে না, যদি xঘোষণার সময় প্রাথমিকভাবে করা হয়:

 goto label;

    int x = 58; //error, jumping over declaration with initialization

    label:
    cout << x << endl;

1

নতুন ভেরিয়েবলগুলি কেবলমাত্র ব্লক স্কোপেই ডিক্লেয়ার করা যায়। আপনাকে এরকম কিছু লিখতে হবে:

case VAL:  
  // This will work
  {
  int newVal = 42;  
  }
  break;

অবশ্যই, নিউওয়ালের কেবল ধনুর্বন্ধনীগুলির মধ্যেই সুযোগ রয়েছে ...

চিয়ার্স, র‌্যাল্ফ


1

একটি switchব্লক ব্লকের উত্তরাধিকারের মতো নয় if/else ifআমি অবাক হয়েছি অন্য কোনও উত্তর এটি পরিষ্কারভাবে ব্যাখ্যা করে না।

এই switchবিবৃতি বিবেচনা করুন :

switch (value) {
    case 1:
        int a = 10;
        break;
    case 2:
        int a = 20;
        break;
}

এটি আশ্চর্যজনক হতে পারে তবে সংকলকটি এটিকে সাধারণ হিসাবে দেখবে না if/else if। এটি নিম্নলিখিত কোড উত্পাদন করবে:

if (value == 1)
    goto label_1;
else if (value == 2)
    goto label_2;
else
    goto label_end;

{
label_1:
    int a = 10;
    goto label_end;
label_2:
    int a = 20; // Already declared !
    goto label_end;
}

label_end:
    // The code after the switch block

caseবিবৃতি লেবেল রূপান্তরিত করা হয় এবং তারপর সাথে ডাকাgoto । বন্ধনীগুলি একটি নতুন সুযোগ তৈরি করে এবং এটি এখনই সহজে দেখা যায় কেন আপনি একটি এর মধ্যে একই নামের সাথে দুটি ভেরিয়েবল ঘোষণা করতে পারবেন নাswitch ব্লকের ।

এটি অদ্ভুত লাগতে পারে তবে পতনের জন্য সমর্থন করা প্রয়োজন ( breakএটি পরবর্তীটিতে কার্যকর হওয়া চালিয়ে যেতে দেয় না case)।


0

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


0

নতুনওয়ালটি স্যুইচের পুরো ক্ষেত্রটিতে বিদ্যমান তবে কেবলমাত্র VAL অঙ্গটি আঘাত করা হলে শুরু করা হয়। আপনি যদি ভ্যালিতে কোডের চারপাশে একটি ব্লক তৈরি করেন তবে এটি ঠিক আছে।


0

সি ++ স্ট্যান্ডার্ডের রয়েছে: কোনও ব্লকে স্থানান্তর করা সম্ভব, তবে এমনভাবে নয় যে সূচনা দিয়ে ঘোষণাকে বাইপাস করে। একটি প্রোগ্রাম যা স্বয়ংক্রিয় স্টোরেজ সময়কাল সহ একটি স্থানীয় ভেরিয়েবল এমন একটি বিন্দুতে স্কোপ করে না যেখানে ভাসিয়েবলের POD টাইপ (3.9) না থাকে এবং ইনিশিয়ালাইজার (8.5) ছাড়াই ঘোষিত না হলে এই স্থানটি অসুস্থ হয় না umps

এই নিয়মটি বর্ণনা করার জন্য কোড:

#include <iostream>

using namespace std;

class X {
  public:
    X() 
    {
     cout << "constructor" << endl;
    }
    ~X() 
    {
     cout << "destructor" << endl;
    }
};

template <class type>
void ill_formed()
{
  goto lx;
ly:
  type a;
lx:
  goto ly;
}

template <class type>
void ok()
{
ly:
  type a;
lx:
  goto ly;
}

void test_class()
{
  ok<X>();
  // compile error
  ill_formed<X>();
}

void test_scalar() 
{
  ok<int>();
  ill_formed<int>();
}

int main(int argc, const char *argv[]) 
{
  return 0;
}

প্রারম্ভকালীন প্রভাব দেখানোর কোড:

#include <iostream>

using namespace std;

int test1()
{
  int i = 0;
  // There jumps fo "case 1" and "case 2"
  switch(i) {
    case 1:
      // Compile error because of the initializer
      int r = 1; 
      break;
    case 2:
      break;
  };
}

void test2()
{
  int i = 2;
  switch(i) {
    case 1:
      int r;
      r= 1; 
      break;
    case 2:
      cout << "r: " << r << endl;
      break;
  };
}

int main(int argc, const char *argv[]) 
{
  test1();
  test2();
  return 0;
}

0

এটি প্রদর্শিত হচ্ছে যে বেনামে অবজেক্টগুলিকে স্যুইচ কেস স্টেটমেন্টে ঘোষণা করা বা তৈরি করা যেতে পারে যার কারণে তাদের রেফারেন্স করা যায় না এবং কারণ এটি পরবর্তী ক্ষেত্রে পড়ে না। জিসিসি 4.5.3 এবং ভিজ্যুয়াল স্টুডিও ২০০৮-এ সংকলিত এই উদাহরণটি বিবেচনা করুন (বিশেষজ্ঞরা দয়া করে এটি বিবেচনা করুন) সুতরাং এটি কমপ্লায়েন্সের সমস্যা হতে পারে)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

    switch( i )
    {
    case 42:
        Foo();  // Apparently valid
        break;

    default:
        break;
    }
    return EXIT_SUCCESS;
}

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

1
ডিভি নয়, তবে: পুরো প্রশ্নটি নামযুক্ত ভেরিয়েবলের ঘোষণার / সুযোগ সম্পর্কে। একটি অস্থায়ী ("বেনামে অবজেক্ট" একটি শব্দ নয়) একটি নামযুক্ত ভেরিয়েবল নয়, এটি কোনও ঘোষণাও নয়, বা এটি সুযোগেরও অধীন নয় (যদি constতার নিজস্ব ক্ষেত্রের সাথে কোনও রেফারেন্সের সাথে আবদ্ধ না থাকে)। এটি এমন একটি বহিঃপ্রকাশ যা তার বিবৃতিতে (যেখানেই হোক না কেন) বাঁচে এবং মরে। অতএব, এটি সম্পূর্ণ অপ্রাসঙ্গিক।
আন্ডারস্কোর_ডি

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