ස්විච් ප්‍රකාශයකින් විචල්‍යයන් ප්‍රකාශ කළ නොහැක්කේ ඇයි?


960

මම නිතරම මෙය කල්පනා කර ඇත්තෙමි - ස්විච් ප්‍රකාශයක සිද්ධි ලේබලයකින් පසුව ඔබට විචල්‍යයන් ප්‍රකාශ කළ නොහැක්කේ ඇයි? C ++ හි ඔබට ඕනෑම තැනක විචල්‍යයන් ප්‍රකාශ කළ හැකිය (ඒවා පළමු භාවිතයට ආසන්න බව ප්‍රකාශ කිරීම පැහැදිලිවම හොඳ දෙයකි) නමුත් පහත සඳහන් දෑ තවමත් ක්‍රියාත්මක නොවේ:

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

ඉහත මට පහත දෝෂය ලබා දෙයි (MSC):

'newVal' ආරම්භ කිරීම 'case' ලේබලය මඟින් මඟ හරිනු ලැබේ

මෙය වෙනත් භාෂාවල ද සීමාවක් බව පෙනේ. මෙය එවැනි ගැටලුවක් වන්නේ ඇයි?


10
සී බීඑන්එෆ් ව්‍යාකරණ මත පදනම් වූ පැහැදිලි කිරීමක් සඳහා, stackoverflow.com/questions/1180550/weird-switch-error-in-obj-c/…
ජෝන්

පොදුවේ ස්විච් ප්‍රකාශ සහ ලේබල් (ABC :) පිළිබඳ හොඳ කියවීමක් මෙන්න .
එතෙරලෝන්

5
මම කියන්නේ 'ප්‍රකාශයට පත් කරනවාට වඩා ස්විච් ප්‍රකාශයකින් විචල්‍යයන් ආරම්භ කළ නොහැක්කේ ඇයි' යන්නයි. විචල්‍යය ප්‍රකාශ කිරීමෙන් මට MSVC හි අනතුරු ඇඟවීමක් පමණක් ලබා දේ.
ZoomIn

Answers:


1159

Caseප්‍රකාශ ලේබල් පමණි . මෙයින් අදහස් කරන්නේ සම්පාදකයා මෙය කෙලින්ම ලේබලය වෙතට පනින බවයි. C ++ හි, මෙහි ගැටළුව විෂය පථයෙන් එකකි. ඔබේ වක්‍ර වරහන් මඟින් switchප්‍රකාශය තුළ ඇති සියල්ල ලෙස විෂය පථය අර්ථ දක්වයි . මෙයින් අදහස් කරන්නේ ඔබට ආරම්භය මඟ හැරෙන කේතයට තවදුරටත් පැනීමක් සිදු කළ හැකි විෂය පථයක් ඇති බවයි.

මෙය හැසිරවිය හැකි නිවැරදි ක්‍රමය නම් එම caseප්‍රකාශයට විශේෂිත විෂය පථයක් නිර්වචනය කර ඒ තුළ ඔබේ විචල්‍යය නිර්වචනය කිරීමයි:

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

94
නව විෂය පථයක් විවෘත කිරීමට සාපේක්ෂව - කියවීමේ හැකියාව සහ කේතයේ අනුකූලතාවයට අනුග්‍රහය දක්වන්න. පැරණි දිනවල, ඔබට ස්වයංක්‍රීයව "අමතර" සිරස් රාමුවක් ලැබෙන්නට ඇත, නමුත් දැන් එය හොඳ ප්‍රශස්තිකරණ සම්පාදකයෙකු සඳහා එසේ නොවිය යුතුය.
උස ජෙෆ්

11
මම ජෙෆ් සමඟ එකඟ වෙමි - බොහෝ අය භාවිතා කරන ඉන්ඩෙන්ටින් විලාසය නිසා ස්විච් ප්‍රකාශයක් කියවීමේදී විෂය පථය "උපකල්පනය කිරීම" පහසු නැත. මගේම ශෛලිය නම්, එක් එක් සිද්ධිය / පෙරනිමිය සඳහා එක් පේළියකට වඩා දිගු නම් සෑම විටම නව විෂය පථයක් විවෘත කිරීමයි.
ලංසු

39
workmad3 - ඔබ නව විචල්‍යයන් ප්‍රකාශ නොකරන්නේ නම් නව සිරස් රාමුවක් ජනනය කරන ඕනෑම C ++ සම්පාදකයෙකු මට සොයාගත හැකිද? ඔබ මා කෙටියෙන් කනස්සල්ලට පත් කළ නමුත් G ++ 3.1, Visual C ++ 7 හෝ Intel C ++ 8 කිසිවක් ඔබ කිසිදු විචල්‍යයක් ප්‍රකාශ නොකරන නව විෂය පථයන් සඳහා කේතයක් ජනනය නොකරනු ඇත.
ක්‍රිස් ජෙෆර්සන්

10
cur workmad3 නව රැලි වරහන් බ්ලොක් එකකට ඇතුළු කිරීමෙන් නව සිරස් රාමුවක් ඇති නොවේ. stackoverflow.com/questions/2759371/…
MTVS

3
AllTallJef ඔබ සඳහන් කරන 'පැරණි දින' මොනවාදැයි මම නොදනිමි. වසර 40 ක් තුළ, ක්‍රමයට ඇතුළු වූ විට ක්‍රමයක් සඳහා සියලු ඉඩ වෙන් නොකෙරෙන සම්පාදකයෙකු මට හමු වී නැත .
මාර්ක්විස් ඔෆ් ලෝර්න්

346

මෙම ප්රශ්නය වන්නේ මුලින් එම අවස්ථාවේ දී [C] සහ [C ++] ලෙස tagged විය. මුල් කේතය ඇත්ත වශයෙන්ම සී සහ සී ++ යන දෙකෙහිම වලංගු නොවේ, නමුත් සම්පූර්ණයෙන්ම වෙනස් සම්බන්ධයක් නැති හේතු නිසා.

  • C ++ හි මෙම කේතය අවලංගු වන්නේ case ANOTHER_VAL:ලේබලය newValඑහි ආරම්භය මඟ හැර විචල්‍යයේ විෂය පථයට පනින බැවිනි . ස්වයංක්‍රීය වස්තූන් ආරම්භ කිරීම මඟ හරින පැනීම C ++ හි නීති විරෝධී ය. ගැටලුවේ මෙම පැත්ත බොහෝ පිළිතුරු මගින් නිවැරදිව ආමන්ත්‍රණය කරනු ලැබේ.

  • කෙසේ වෙතත්, සී භාෂාවෙන් විචල්ය ආරම්භක මග හැරීම දෝෂයක් නොවේ. විචල්‍යයක ආරම්භයට වඩා එහි විෂය පථයට පැනීම සී හි නීත්‍යානුකූල වේ. එයින් අදහස් කරන්නේ විචල්‍යය ආරම්භ නොවී ඉතිරිව ඇති බවයි. මුල් කේතය සම්පූර්ණයෙන්ම වෙනස් හේතුවක් නිසා C හි සම්පාදනය නොවේ. case VAL:මුල් කේතයේ ලේබලය විචල්ය ප්රකාශයට අමුණා ඇත newVal. සී භාෂාවෙන් ප්‍රකාශ යනු ප්‍රකාශ නොවේ. ඒවා ලේබල් කළ නොහැක. මෙම කේතය සී කේතය ලෙස අර්ථ නිරූපණය කිරීමේදී දෝෂයට හේතුව මෙයයි.

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

අමතර වාරණයක් එකතු කිරීම මඟින් {}C ++ සහ C යන ගැටලු දෙකම විසඳනු ඇත, මෙම ගැටළු බොහෝ වෙනස් වුවද. C ++ පැත්තේ එය විෂය පථය සීමා කරයි, එම විෂය පථයට තවදුරටත් පනින්නේ නැති newValබවට වග බලා ගන්න case ANOTHER_VAL:, එමඟින් C ++ ගැටළුව ඉවත් කරයි. සී පැත්තේ අතිරේක {}සංයෝග ප්‍රකාශයක් හඳුන්වා දෙන අතර එමඟින් case VAL:ලේබලය ප්‍රකාශයකට අදාළ වන අතර එමඟින් සී ගැටළුව ඉවත් වේ.

  • සී නඩුවේදී ගැටළුව පහසුවෙන් විසඳා ගත හැකිය {}. case VAL:ලේබලය පසු හිස් ප්‍රකාශයක් එක් කරන්න, එවිට කේතය වලංගු වේ

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

    එය දැන් C දෘෂ්ටි කෝණයෙන් වලංගු වුවද, එය C ++ දෘෂ්ටි කෝණයෙන් වලංගු නොවන බව සලකන්න.

  • සමමිතිකව, C ++ නඩුවේදී ගැටළුව පහසුවෙන් විසඳා ගත හැකිය {}. ආරම්භක ප්‍රකාශය විචල්‍ය ප්‍රකාශනයෙන් ඉවත් කරන්න, එවිට කේතය වලංගු වේ

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

    එය දැන් C ++ දෘෂ්ටි කෝණයෙන් වලංගු වුවද, එය C දෘෂ්ටි කෝණයෙන් වලංගු නොවන බව සලකන්න.


4
NAnT: C ++ නිවැරදි කරන එක C සඳහා අදාළ නොවන්නේ මන්දැයි මට තේරේ; කෙසේ වෙතත්, ආරම්භකත්වය මඟ හැරීමේ C ++ ගැටළුව එය නිවැරදි කරන්නේ කෙසේදැයි මට තේරුම් ගත නොහැක. newValඑය පනින විට ප්‍රකාශ කිරීම සහ පැවරීම තවමත් මඟ හැරෙන්නේ ANOTHER_VALනැද්ද?
legends2k

14
@ legends2k: ඔව්, එය තවමත් මඟ හැරේ. කෙසේ වෙතත්, මම "එය ගැටළුව විසඳයි" යැයි පැවසූ විට, මම අදහස් කළේ එය C ++ සම්පාදක දෝෂය නිවැරදි කරන බවයි. C ++ හි ආරම්භකය සමඟ පරිමාණ ප්‍රකාශයක් මඟ හැරීම නීති විරෝධී ය , නමුත් ආරම්භකයකු නොමැතිව පරිමාණ ප්‍රකාශයක් මඟ හැරීම ඉතා සුදුසුය . දී case ANOTHER_VAL:අවස්ථාවක විචල්ය newValදෘශ්යමාන, නමුත් අවිනිශ්චිතතාවයෙන් පෙලෙන අගය වේ.
AnT

3
සිත් ඇදගන්නා සුළු ය. §A9.3: Compound Statementකේ ඇන්ඩ් ආර් සී (දෙවන සංස්කරණය) කියවීමෙන් පසුව මට මෙම ප්‍රශ්නය හමු විය . ඇතුළු වීම සඳහා තාක්ෂණික නිර්වචනය සඳහන් සංයෝගයක්-ප්රකාශයක් වන {declaration-list[opt] statement-list[opt]}. ව්‍යාකූලත්වයට පත්වී ඇත්තේ ප්‍රකාශයක් ප්‍රකාශයක් යැයි මා සිතූ නිසා, මම එය සොයා බැලූ වහාම මෙම ප්‍රශ්නය සොයා ගතිමි. උදාහරණයකට අසමානතාවය පැහැදිලිව පෙනෙන අතර වැඩසටහනක් බිඳ දමයි . තවත් විසඳුමක් (සී සඳහා) ප්‍රකාශයට පෙර තවත් ප්‍රකාශයක් (සමහර විට ශුන්‍ය ප්‍රකාශයක් විය හැකිද?) ලේබල් කරන ලද ප්‍රකාශය සෑහීමකට පත්වේ යැයි මම විශ්වාස කරමි .
බ්‍රැඩන් හොඳම

1
අපොයි, මා යෝජනා කළ ශුන්‍ය ප්‍රකාශන විසඳුම දැනටමත් ඔබේ පිළිතුරේ ඇති බව මම දුටුවෙමි. කමක් නෑ එසේනම්.
බ්‍රැඩන් හොඳම

4
හිස් ප්‍රකාශයක් එකතු කිරීම නිවැරදි වන්නේ C99 සඳහා පමණක් බව සඳහන් කිරීම වටී. C89 හි, විචල්‍යයන් ඒවායේ කොටු කොටසේ ආරම්භයේදීම ප්‍රකාශ කළ යුතුය.
ආතර් ටකා

137

හරි. මෙය පැහැදිලි කිරීම සඳහා ප්‍රකාශයට කිසිදු සම්බන්ධයක් නැත. එය සම්බන්ධ වන්නේ "ආරම්භයට ඉහළින් පැනීම" (ISO C ++ '03 6.7 / 3)

මෙහි බොහෝ පෝස්ට් වල සඳහන් කර ඇත්තේ ප්‍රකාශය උඩින් පැනීම විචල්‍ය "ප්‍රකාශ නොකිරීමට" හේතු විය හැකි බවයි. මෙය සත්‍ය නොවේ. ආරම්භකයකු නොමැතිව POD වස්තුවක් ප්‍රකාශ කළ හැකි නමුත් එයට අවිනිශ්චිත අගයක් ඇත. උදාහරණයක් වශයෙන්:

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;
}

වස්තුව POD නොවන හෝ සම්පාදකයා සමාරම්භක කාරකයක් එක් කරන අතර එමඟින් එවැනි ප්‍රකාශයක් උඩින් පනින්න බැහැ:

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:
  ;

සුළු සුළු කාරණයක් නම් මෙය C ++ සහ C අතර වෙනසක් වීමයි. C හි, ආරම්භයට ඉහළින් පැනීම දෝෂයක් නොවේ.

අනෙක් අය සඳහන් කර ඇති පරිදි, විසඳුම වන්නේ විචල්යයේ ආයු කාලය තනි සිද්ධි ලේබලයට පමණක් සීමා වන පරිදි කූඩු බ්ලොක් එකක් එකතු කිරීමයි.


2
"ආරම්භයට වඩා පැනීමේ දෝෂයක්" ??? මගේ GCC සමඟ නොවේ. පහත දැක්වෙන ලේබලය භාවිතා කරන විට එය "j ඒකීයකරණය කළ හැකි" අනතුරු ඇඟවීමක් ලබා දිය හැකි නමුත් දෝෂයක් නොමැත. කෙසේ වෙතත්, මාරුවීමේදී දෝෂයක් ඇත (දෘ error දෝෂයක්, දුර්වල අනතුරු ඇඟවීමක් නොවේ).
මැකී

9
E මෙකී: එය C ++ හි නීති විරෝධී ය. ISO C ++ '03 - 6.7 / 3: "... විචල්යයට POD වර්ගය නොමැති නම්, ස්වයංක්‍රීය ගබඩා කාල සීමාවක් සහිත දේශීය විචල්යයක් විෂය පථයට අයත් නොවන ස්ථානයකට පනින වැඩසටහනකි. (3.9) වන අතර එය ආරම්භකයකු නොමැතිව ප්‍රකාශයට පත් කෙරේ (8.5).
රිචඩ් කෝර්ඩන්

1
ඔව්, නමුත් එය සී හි නීති විරෝධී නොවේ (අවම වශයෙන් gcc එය එසේ නොවන බව පවසයි). j ආරම්භ නොකෙරේ (අහඹු අංකයක් ඇත), නමුත් සම්පාදකයා එය සම්පාදනය කරයි. කෙසේ වෙතත්, ස්විච් ප්‍රකාශය සම්බන්ධයෙන්, සම්පාදකයා එය සම්පාදනය නොකරනු ඇති අතර ගොටෝ / ලේබල් නඩුවක් සහ ස්විච් නඩුවක් අතර වෙනස දැකීමට මා අසමත් වේ.
මැකී

8
E මෙකී: පොදුවේ තනි සම්පාදක හැසිරීමක් භාෂාවෙන් සත්‍ය වශයෙන්ම අවසර දී ඇති දේ පිළිබිඹු නොකරයි. මම C'90 සහ C'99 යන දෙකම පරික්ෂා කර ඇති අතර ප්‍රමිති දෙකටම ස්විච් ප්‍රකාශයක ආරම්භය ඉක්මවා යාමේ උදාහරණයක් ඇතුළත් වේ.
රිචඩ් කෝර්ඩන්

38

සම්පූර්ණ ස්විච් ප්‍රකාශය එකම විෂය පථයක පවතී. එය වටා යාමට, මෙය කරන්න:

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

    case ANOTHER_VAL:
      ...
    break;
}

වරහන් සටහන් කරන්න.


30

සියලු පිළිතුරු සහ තවත් පර්යේෂණ කිහිපයක් කියවීමෙන් පසු මට කරුණු කිහිපයක් ලැබේ.

Case statements are only 'labels'

C හි, පිරිවිතරයන්ට අනුව,

§6.8.1 ලේබල් කරන ලද ප්‍රකාශ:

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

C හි “ලේබල් කරන ලද ප්‍රකාශයක්” සඳහා ඉඩ දෙන කිසිදු වගන්තියක් නොමැත. එය භාෂාවේ කොටසක් පමණක් නොවේ.

නිසා

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

මෙය සම්පාදනය නොකරනු ඇත , http://codepad.org/YiyLQTYw බලන්න . GCC දෝෂයක් ලබා දෙයි:

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 . මෙන්න මමත් එම දෝෂය ලබා ගනිමි.


C ++ හි, පිරිවිතරයන්ට අනුව,

ලේබල්-ප්‍රකාශනයට අවසර ඇත, නමුත් ලේබල් කරන ලද-ආරම්භකකරණයට අවසර නැත.

Http://codepad.org/ZmQ0IyDG බලන්න .


එවැනි තත්වයකට විසඳුම දෙකකි

  1. විෂය පථය using 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
ඔබ සී ප්‍රශ්නය නිවැරදිව විස්තර කර ඇත. නමුත් C ++ ලේබල් කරන ලද ආරම්භයට අවසර නැතැයි යන ප්‍රකාශය සම්පූර්ණයෙන්ම සත්‍ය නොවේ. C ++ හි ලේබල් කරන ලද ආරම්භයේ කිසිදු වරදක් නොමැත. C ++ ඉඩ නොදෙන දෙය නම් විචල්‍යයේ විෂය පථයට විචල්යය ආරම්භ කිරීම ඉක්මවාa යාමයි a. එබැවින්, සී දෘෂ්ටි කෝණයෙන්, ගැටළු case VAL:ලේබලය සමඟ ඇති අතර ඔබ එය නිවැරදිව විස්තර කර ඇත. නමුත් C ++ දෘෂ්ටි කෝණයෙන් බලන විට ගැටළුව ඇත්තේ case ANOTHER_VAL:ලේබලය සමඟ ය .
AnT

C ++ හි, C මෙන් නොව, ප්‍රකාශන යනු ප්‍රකාශයන්ගේ උප කුලකයකි.
කීත් තොම්සන්

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
මෙම ඩෆ්ගේ උපාංග ක්‍රියාත්මක කිරීමේදී දෝෂයක් ඇති අතර එය අතිශය මන්දගාමී වේ: ගණනය කිරීම int වර්ගය වන බැවින්% සත්‍ය බෙදීම් / මොඩියුලෝ මෙහෙයුමක් කළ යුතුය. අත්සන් නොකල ගණනය කරන්න (හෝ වඩා හොඳ තවමත්, සෑම විටම ගණන් / දර්ශක සඳහා size_t භාවිතා කරන්න) එවිට ගැටළුව පහව යයි.
ආර් .. GitHub STOP HELPING ICE

1
@R ..: මොකක්ද ?! දෙදෙනෙකුගේ අනුපූරක පද්ධතියක් තුළ, අත්සන් කිරීම 2 බලයෙන් මොඩියුලයට බලපාන්නේ නැත (එය පහළ සහ පහළ බිටු වල පමණි), සහ ඔබේ ප්‍රොසෙසර් ගෘහ නිර්මාණ ශිල්පයට අංක ගණිත දකුණ මාරුවීමේ මෙහෙයුමක් පවතින තාක් කල් 2 බලයෙන් බෙදීම් වලට එය බලපාන්නේ නැත. ( SARx86 හි, SHRඅත්සන් නොකළ මාරුවලට එදිරිව ).
ක්‍රිස් ජෙස්ටර්-යං

H ක්‍රිස්: මම විශ්වාස කරන්නේ සම්පාදකයා විසින් negative ණ අගයන් සඳහා ඉඩ දිය යුතු විට “පහළ සහ පහළ බිටු පමණක්” නොතිබිය යුතු බවයි. උදාහරණයක් ලෙස, -1 ++ 8 මෙම ++ හි අනුපූරක පද්ධතියට g ++ භාවිතා කරයි -1 (මෙම නඩුවේ ලකුණ 5.6 / 4 අනුව ක්‍රියාත්මක කිරීම අර්ථ දක්වා ඇත).

3
H ක්‍රිස්: ආර් බලපෑම අතිශයෝක්තියට නංවන බව මම ඔබ සමඟ එකඟ වෙමි. මම ඔබේ අදහස දුටුවෙමි, සරල දෙයක් දැන සිටියෙමි, එය ප්‍රමාණවත් නොවීය.

1
මතක තබා ගත යුතු කරුණක් වන්නේ මුල් විකිපීඩියා කේතය මතක සිතියම්ගත කළ නිමැවුමකට දත්ත යැවීමයි. එය මෙහි අමුතු ලෙස පෙනෙන්නේ එය සඳහන් කර නැති නිසා සහ සෑම බයිටයක්ම එකම “සිට” ස්ථානයට පිටපත් කර ඇති බැවිනි. පෝස්ට්ෆික්ස් ++ ට එකතු කිරීමෙන් හෝ භාවිත නඩුව සඳහන් කිරීමෙන් මතක සිතියම්ගත කළ අයි.ඕ. මුල් ප්‍රශ්නයට සම්පූර්ණයෙන්ම පර්යන්ත :-).
පීටර්

16

මේ දක්වා ඇති බොහෝ පිළිතුරු එක් ආකාරයකින් වැරදියි: සිද්ධි ප්‍රකාශයෙන් පසුව ඔබට විචල්‍යයන් ප්‍රකාශ කළ හැකිය , නමුත් ඔබට ඒවා ආරම්භ කළ නොහැක :

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

කලින් සඳහන් කළ පරිදි, මේ සඳහා හොඳ ක්‍රමයක් වන්නේ ඔබේ නඩුව සඳහා විෂය පථයක් නිර්මාණය කිරීම සඳහා වරහන් භාවිතා කිරීමයි.


1
32 මහතා ඔබේ වැරැද්ද කුමක්දැයි ඔබ වරදවා වටහාගෙන ඇත: ඔව් එය සම්පාදනය කිරීමට යන්නේ නැත, නමුත් ඔබ ස්විචයක් තුළ විචල්‍යයක් ප්‍රකාශ කරන නිසා නොවේ. දෝෂය වන්නේ ඔබ ප්‍රකාශයකින් පසු විචල්‍යයක් ප්‍රකාශ කිරීමට උත්සාහ කරන නිසා එය සී හි නීති විරෝධී ය.
මිස්ටර් සීබ්‍රා

1
දැන් c90 හි නීත්‍යානුකූල වන දින සහ c
Jeegar Patel

12

මගේ ප්‍රියතම නපුරු ස්විච් උපක්‍රමය නම් අනවශ්‍ය සිද්ධි ලේබලයක් මඟ හැරීම සඳහා if (0) භාවිතා කිරීමයි.

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

නමුත් ඉතා නපුරු ය.


ඉතා කදිමයි. එයට හේතුව: නඩුව 0 සහ නඩුව 1 උදාහරණයක් ලෙස විචල්‍යයක් ආරම්භ කිරීම 2 වැනි අවස්ථාවෙහිදී භාවිතා කළ හැකිය.
hlovdal

1
ඔබට කේස් 0 සහ කේස් 1 යන දෙකම කේස් 2 හරහා වැටීමට අවශ්‍ය නම්. එය සැබවින්ම ප්‍රයෝජනවත් දැයි නොදනී, නමුත් නිසැකවම ක්‍රියාත්මක වේ.
පෙට්රූසා

1
gotoකේතය
අපැහැදිලි


7

ඔබ නව වාරණයක් ආරම්භ කරන්නේ නම් ඔබට ස්විච් ප්‍රකාශයක් තුළ විචල්‍යයන් ප්‍රකාශ කළ හැකිය :

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

හේතුව දේශීය විචල්‍යය (ය) ගබඩා කිරීම සඳහා තොගයේ ඉඩ වෙන් කිරීම (සහ නැවත ලබා ගැනීම) කිරීමයි.


1
විචල්‍යය ප්‍රකාශ කළ හැකි නමුත් එය ආරම්භ කළ නොහැක. එසේම, මෙම ගැටළුව කෙසේ හෝ තොගයට හා දේශීය විචල්‍යයන්ට සම්බන්ධ නොවන බව මට හොඳටම විශ්වාසයි.
රිචඩ් කෝර්ඩන්

6

සලකා බලන්න:

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

විවේක ප්‍රකාශ නොමැති විට, සමහර විට නිව්වාල් දෙවරක් ප්‍රකාශයට පත් වන අතර, එය ක්‍රියාත්මක වන තෙක් එය කරන්නේ දැයි ඔබ නොදනී. මගේ අනුමානය නම් සීමාව මේ ආකාරයේ ව්‍යාකූලතා නිසා බවයි. NewVal හි විෂය පථය කුමක් වනු ඇත්ද? සම්මුතිය මගින් නියම කරනුයේ එය සමස්ත ස්විච් බ්ලොක් එක (වරහන් අතර) බවයි.

මම සී ++ ක්‍රමලේඛකයෙක් නොව සී:

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

හොඳින් වැඩ කරයි. ස්විච් බ්ලොක් එකක් තුළ විචල්‍යයක් ප්‍රකාශ කිරීම හොඳයි. නඩු මුරකරුවෙකුගෙන් පසුව ප්‍රකාශ කිරීම නොවේ.


3
32 Mr.32: ඇත්ත වශයෙන්ම ඔබේ උදාහරණයෙන් පෙන්නුම් කරන්නේ printf ක්‍රියාත්මක නොවන බවයි, නමුත් මේ අවස්ථාවේ දී, int x යනු ප්‍රකාශයක් නොව ප්‍රකාශයක්, x ප්‍රකාශයට පත් කිරීම, ක්‍රියාකාරී පරිසරය ගොඩගැසී ඇති සෑම අවස්ථාවකම ඒ සඳහා ඉඩ වෙන් කර ඇත, බලන්න: codepad.org/4E9Zuz1e
පෙට්රූසා

ප්‍රශ්නයේ මාතෘකාව කියවීමේදී මෙය සොයා ගැනීමට මම අපේක්ෂා කළෙමි, මන්ද ප්‍රශ්නය "නඩුව:" ලේබල තුළ විචල්‍යයන් ප්‍රකාශ කිරීම ගැන නොව ස්විච් ප්‍රකාශ වලින් ය. ස්විච් ප්‍රකාශ වල විචල්‍යයන් ගැන ඇත්ත වශයෙන්ම කතා කළේ ඔබ (සහ වික්ටර්එච්, ඔබේ පිළිතුර අවධාරණය කරමින්) පමණි.
cesss

4

ස්විචයේ සම්පූර්ණ කොටස තනි ප්‍රකාශන සන්දර්භයකි. එවැනි ප්‍රකාශයක විචල්‍යයක් ප්‍රකාශ කළ නොහැක. ඒ වෙනුවට මෙය උත්සාහ කරන්න:

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

විචල්‍යය ප්‍රකාශ කළ හැකි නමුත් එය ආරම්භ කළ නොහැක.
රිචඩ් කෝර්ඩන්

Ic රිචඩ් කෝර්ඩන් ආරම්භ කිරීම සාර්ථක වනු ඇතැයි මට විශ්වාසයි. එය ආරම්භ කළ නොහැකි බව ඔබ තවමත් කියා සිටිනවාද?
chux - මොනිකා නැවත ස්ථාපනය කරන්න

3

ඔබේ කේතය "int newVal = 42" යැයි පැවසුවහොත්, NewVal කිසි විටෙකත් ආරම්භක නොවන බව ඔබ සාධාරණ ලෙස අපේක්ෂා කරනු ඇත. නමුත් ඔබ මෙම ප්‍රකාශය ඉක්මවා ගියහොත් (ඔබ කරන්නේ එයයි) එවිට හරියටම සිදුවන්නේ එයයි - newVal විෂය පථයට අයත් නමුත් පවරා නොමැත.

ඔබ සැබවින්ම සිදුවීමට අදහස් කළේ එය නම්, "int newVal; newVal = 42;" යනුවෙන් පවසමින් භාෂාවට එය පැහැදිලි කළ යුතුය. එසේ නොමැතිනම් ඔබට නව වෝල් හි විෂය පථය තනි නඩුවකට සීමා කළ හැකිය, එය ඔබට අවශ්‍ය දේට වඩා වැඩි ය.

ඔබ එකම උදාහරණය සලකා බැලුවද "const int newVal = 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; කිසි විටෙකත් ක්‍රියාත්මක නොවේ. මෙම codepad.org/PA1quYX3
ජීගර් පටෙල්

4
ප්‍රකාශය ක්‍රියාත්මක int newVal කරනු ඇත, නමුත් = 42පැවරුම නොවේ .
පෙට්රුසා

3

මෙතෙක් පිළිතුරු ලැබී ඇත්තේ C ++ සඳහා ය.

C ++ සඳහා, ඔබට ආරම්භයක් ඉක්මවා යා නොහැක. ඔබට සී හි සිටිය හැකිය. කෙසේ වෙතත්, සී හි ප්‍රකාශයක් ප්‍රකාශයක් නොවන අතර සිද්ධි ලේබල් ප්‍රකාශන අනුගමනය කළ යුතුය.

ඉතින්, වලංගු (නමුත් කැත) සී, අවලංගු සී ++

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();
}

අනෙක් අතට, C ++ හි ප්‍රකාශයක් ප්‍රකාශයකි, එබැවින් පහත දැක්වෙන්නේ වලංගු C ++, අවලංගු සී

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

1
දෙවන උදාහරණය වලංගු නොවන C ++ (vc2010 සහ gcc 4.6.1 C ++ සමඟ පරීක්‍ෂා කිරීම ආරම්භක කොටස මඟ හැරීමට ඉඩ නොදේ. Gcc දෝෂ පණිවිඩය: 'int i' හි හරස් ආරම්භය
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;
}

නිවැරදි කිරීම ප්‍රමාණවත් තරම් සරල බව මට වැටහී ඇත, නමුත් පළමු උදාහරණය සම්පාදකයාට කරදර නොවන්නේ මන්දැයි මට තවම වැටහෙන්නේ නැත. කලින් සඳහන් කළ පරිදි (අවුරුදු 2 කට පෙර හෙහෙ) ප්‍රකාශනය යනු තර්කනය නොතකා දෝෂයට හේතුව නොවේ. ආරම්භය යනු ගැටළුවයි. විචල්‍යය ආරම්භ කර විවිධ රේඛාවලින් ප්‍රකාශ කරන්නේ නම් එය සම්පාදනය කරයි.


1
පළමුව gcc 4.2 හි හොඳ නැත: "දෝෂය: 'int' ට පෙර අපේක්ෂිත ප්‍රකාශනය". පීටර් සහ මිස්ටර් 32 පවසන පරිදි, "නඩුව 0 :; int j; ..." සහ "නඩුව 0 :; int j = 7; ..." යන දෙකම ක්‍රියාත්මක වේ. C හි ගැටළුව වන්නේ "නඩුව <label>: ප්‍රකාශනය" වලංගු නොවන C වාක්‍ය ඛණ්ඩයකි.
dubiousjim

3

මෙම ප්‍රශ්නය සඳහා මම මෙම පිළිතුර මුලින් ලියා ඇත. කෙසේ වෙතත් මම එය අවසන් කළ විට එම පිළිතුර වසා ඇති බව මට පෙනී ගියේය. එබැවින් මම එය මෙහි පළ කළෙමි, සමහර විට සම්මතයට යොමු වීමට කැමති කෙනෙකුට එය ප්‍රයෝජනවත් වනු ඇත.

ප්‍රශ්නයේ මුල් කේතය:

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

ඇත්ත වශයෙන්ම ප්‍රශ්න 2 ක් ඇත:

1. caseලේබලයෙන් පසු මට විචල්‍යයක් ප්‍රකාශ කළ හැක්කේ ඇයි ?

එයට හේතුව C ++ ලේබලයේ ස්වරූපයෙන් තිබිය යුතු බැවිනි:

එන් 3337 6.1 / 1

ලේබල් කළ ප්‍රකාශය:

...

  • attribute-specifier-seqopt case constant-expression :statement

...

හා C++ ප්රකාශ ප්රකාශයක් ද ලෙස සැලකිය යුතු වේ ප්රකාශයක් (විරුද්ධ ලෙස C):

N3337 6/1:

ප්‍රකාශය :

...

ප්‍රකාශන-ප්‍රකාශය

...

2. මට විචල්‍ය ප්‍රකාශනය ඉක්මවා ගොස් එය භාවිතා කළ හැක්කේ ඇයි?

මොකද: 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

මම විශ්වාස කරන්නේ දැනට පවතින ගැටලුව නම් එම ප්‍රකාශය මඟ හැරී ඇති අතර ඔබ වෙනත් තැනක var භාවිතා කිරීමට උත්සාහ කළහොත් එය ප්‍රකාශ නොවනු ඇත.


0

newVal ස්විචයේ මුළු විෂය පථය තුළම පවතින නමුත් ආරම්භ කරනු ලබන්නේ VAL අවයවයට පහර දුන්නොත් පමණි. ඔබ VAL හි කේතය වටා බ්ලොක් එකක් නිර්මාණය කරන්නේ නම් එය හරි විය යුතුය.


0

සී ++ ස්ටෑන්ඩර්ඩ් සතුව ඇත්තේ: බ්ලොක් එකකට මාරු කළ හැකි නමුත් ආරම්භකත්වය සමඟ ප්‍රකාශන මඟහරින ආකාරයකින් නොවේ. විචල්යයට POD වර්ගය (3.9) නොමැති නම් සහ ආරම්භක (8.5) නොමැතිව ප්රකාශයට පත් නොවන්නේ නම්, ස්වයංක්රීය ගබඩා කාල සීමාවක් සහිත දේශීය විචල්යයක් විෂය පථයට අයත් නොවන ස්ථානයකට පනින වැඩසටහනක් වැරදි ලෙස සකස් වී ඇත.

මෙම රීතිය නිරූපණය කිරීමේ කේතය:

#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

නිර්නාමික වස්තූන් ස්විච් කේස් ප්‍රකාශයකින් ප්‍රකාශ කිරීමට හෝ නිර්මාණය කිරීමට හැකි බව පෙනී යන්නේ ඒවා යොමු කළ නොහැකි නිසා සහ ඊළඟ නඩුවට නොපැමිණෙන බැවිනි. මෙම උදාහරණය GCC 4.5.3 සහ විෂුවල් ස්ටුඩියෝ 2008 සමඟ සම්පාදනය කිරීම සලකා බලන්න (අනුකූලතා ගැටලුවක් විය හැකිය, එබැවින් විශේෂ experts යන් කරුණාකර කිරා මැන බලන්න)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

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

    default:
        break;
    }
    return EXIT_SUCCESS;
}

ඔබ එය ඡන්දය දීමට යන්නේ නම් කරුණාකර එයට හේතුව පැහැදිලි කරන්න. නිර්නාමික වස්තුවක් නිර්මාණය කිරීම නිදහස් කිරීමක් ලෙස පෙනෙන්නේ මන්දැයි දැන ගැනීමට මට කුතුහලයක් ඇත.
ඔලුමයිඩ්

1
DV එකක් නොවේ, නමුත්: සමස්ත ප්‍රශ්නය නම් කරන ලද විචල්‍යයන්ගේ ප්‍රකාශය / විෂය පථයයි. තාවකාලික ("නිර්නාමික වස්තුවක්" යනු පදයක් නොවේ) නම් කරන ලද විචල්‍යයක් නොවේ, එය ප්‍රකාශයක් හෝ විෂය පථයට යටත් නොවේ ( constතමන්ගේම විෂය පථය සමඟ යොමු කිරීමකට බැඳී නොමැති නම් ). එය ප්‍රකාශය තුළ ජීවත්වන හා මිය යන ප්‍රකාශනයකි (එය කොතැනක සිටියත්). එබැවින් එය සම්පූර්ණයෙන්ම අදාල නොවේ.
underscore_d

Foo();ප්‍රකාශයක් නොවේ; ප්රශ්නය ප්රකාශයන් ගැන ය.
එම්එම්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.