programing

스위치 문: 기본값은 마지막 대/소문자여야 합니다.

yoursource 2022. 8. 27. 15:09
반응형

스위치 문: 기본값은 마지막 대/소문자여야 합니다.

의 것을 생각해 보세요.switch★★★★★★★★

switch( value )
{
  case 1:
    return 1;
  default:
    value++;
    // fall-through
  case 2:
    return value * 2;
}

이 코드는 컴파일되지만 C90/C99에 대해 유효한(= 정의 동작) 코드입니까?디폴트 케이스가 마지막 케이스가 아닌 코드를 본 적이 없습니다.

★★★★★★
케이지와 킬리언으로서DS write: 이것은 정말 추악하고 혼란스러운 코드이며 나는 그것을 잘 알고 있다.일반적인 구문(정의되어 있습니까?)과 예상되는 출력에 관심이 있을 뿐입니다.

case 스테이트먼트와 default 스테이트먼트는 스위치스테이트먼트의 임의의 순서로 실행할 수 있습니다.default 구는 대소문자의 상수가 모두 일치하지 않는 경우 대조되는 옵션 구입니다.

좋은 예:-

switch(5) {
  case 1:
    echo "1";
    break;
  case 2:
  default:
    echo "2, default";
    break;
  case 3;
    echo "3";
    break;
}


Outputs '2,default'

케이스가 코드 내에서 논리적인 순서로 제시되고(케이스 1, 케이스 3, 케이스 2/디폴트라고 하는 것은 아니고), 케이스가 매우 길기 때문에, 디폴트에 대해서 케이스 코드 전체를 반복하고 싶지 않은 경우에 매우 편리합니다.

C99 표준은 이에 대해 명시적이지 않지만, 모든 사실을 종합해 보면 완전히 유효하다.

A case ★★★★★★★★★★★★★★★★★」default은 라은 label label label label label label label 에 해당합니다.goto6.8.1로 하다Duff's Device 6.8.1.4.

임의의 문 앞에 ID를 라벨명으로 선언하는 프레픽스를 붙일 수 있습니다.라벨 자체는 제어 흐름을 변경하지 않으며 제어 흐름은 방해받지 않고 계속됩니다.

편집: 스위치 내의 코드는 특별한 것이 아니라 표준 코드 블록입니다.if, 점프 포함.- 「 」 「 」 「 」 、 「 」과 그 를 설명합니다.break수입니니다다

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인 오브젝트는 자동기억기간(블록 내)으로 존재하지만 결코 초기화되지 않기 때문에 제어식이 0이 아닌 값을 가지면 printf 함수에 대한 호출은 불확정값에 접근한다.마찬가지로 함수 f에 대한 호출에 도달할 수 없습니다.

대소문자 상수는 스위치문 내에서 고유해야 합니다.

6.8.4.2.3 각 케이스 라벨의 표현은 정수 상수 표현이어야 하며, 동일한 스위치 문장의 두 개의 케이스 상수 표현은 변환 후 동일한 값을 가져야 한다.스위치 문에는 최대 1개의 디폴트라벨이 존재할 수 있습니다.

모든 경우를 평가한 후 다음과 같은 경우 기본 레이블로 이동합니다.

6.8.4.2.5 정수 승진은 제어식에 대해 수행된다.각 케이스 라벨의 상수식은 제어식의 승격된 유형으로 변환됩니다.변환된 값이 승격된 제어식의 값과 일치하면 대조되는 대/소문자 레이블 뒤에 있는 문장으로 이동합니다.그렇지 않으면 기본 레이블이 있는 경우 컨트롤이 레이블이 지정된 문으로 이동합니다.변환된 대소문자 상수식이 일치하지 않고 기본 라벨이 없는 경우 스위치 본체의 일부가 실행되지 않습니다.

이것은 유효하고 경우에 따라서는 매우 유용합니다.

다음 코드를 고려합니다.

switch(poll(fds, 1, 1000000)){
   default:
    // here goes the normal case : some events occured
   break;
   case 0:
    // here goes the timeout case
   break;
   case -1:
     // some error occurred, you have to check errno
}

은 위의 코드보다 입니다.if· 「 」를 붙일 수 default하기 때문에 .default

예시는 별로 요, 이 예에서는요.poll최대 몇 개의 이벤트가 발생할 수 있는지 알 수 있습니다.내 진짜 요점은 입력값의 정의된 집합이 '예외'와 일반 케이스가 있는 경우가 있다는 것이다.예외나 일반적인 경우를 전면에 내세우는 것이 더 나은지 여부는 선택의 문제이다.

소프트웨어 분야에서는 다른 매우 일반적인 경우를 생각해 보겠습니다.단말기 값의 재귀입니다.스위치를 사용하여 표현할 수 있다면default는, 재귀 콜과 식별 요소(개별의 경우)를 포함한 통상의 값이 됩니다.일반적으로 터미널 값에 초점을 맞출 필요가 없습니다.

또 다른 이유는 컴파일된 코드의 동작이 케이스의 순서로 변경되어 퍼포먼스가 중요하기 때문입니다.대부분의 컴파일러는 컴파일된 어셈블리코드를 스위치에 표시되는 것과 같은 순서로 생성합니다.첫 번째 케이스는 다른 케이스와 크게 다릅니다.첫 번째 케이스 이외의 모든 케이스는 점프를 수반하여 프로세서 파이프라인이 비게 됩니다.스위치로 최초로 출현한 케이스가 실행되도록 디폴트로 브런치프레딕터가 설정되어 있는 것처럼 이해할 수 있습니다.다른 경우보다 훨씬 흔한 경우라면 첫 번째 경우로 상정할 만한 충분한 이유가 있습니다.

코멘트를 읽어보면, 오리지날 포스터가 코드 최적화에 관한 인텔·컴파일러·브런치·루프의 재구성을 읽고 나서, 이 질문을 한 구체적인 이유입니다.

그 후, 코드 가독성과 코드 성능의 어느 정도의 조정이 됩니다.미래의 독자들에게 왜 사건이 먼저 나타나는지 설명하는 댓글을 다는 것이 좋을 것이다.

스위치 문에는 순서가 정의되어 있지 않습니다.당신은 사건들을 이름 있는 라벨과 같은 것으로 볼 수 있다.goto라벨. 여기서 사람들이 생각하는 것과 달리 값 2의 경우 기본 라벨은 점프하지 않습니다.고전적인 예를 들어 설명하자면, 여기 더프의 장치가 있다. 더프는 극단의 상징이다.switch/case주식회사.

send(to, from, count)
register short *to, *from;
register count;
{
  register 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);
  }
}

네, 이것은 유효하고, 상황에 따라서는 편리하기도 합니다.일반적으로 필요하지 않으면 하지 마세요.

defaultcondition은 스위치 내에서 case구가 존재할 수 있는 임의의 장소를 지정할 수 있습니다.마지막 절이 될 필요는 없다.디폴트를 첫 번째 절로 하는 코드를 보았습니다.case 2:default 구가 위에 있어도 정상적으로 실행됩니다.

테스트로 샘플 코드를 함수에 넣었습니다.test(int value){}★★★★

  printf("0=%d\n", test(0));
  printf("1=%d\n", test(1));
  printf("2=%d\n", test(2));
  printf("3=%d\n", test(3));
  printf("4=%d\n", test(4));

출력은 다음과 같습니다.

0=2
1=1
2=4
3=8
4=10

, ' 좋다'는 것이 입니다.default스위치 스테이트먼트의 끝 이외의 장소에 있는 케이스는, 무효인 상태가 머신을 리셋 해, 초기 상태와 같이 진행됩니다.예를 들어 다음과 같습니다.

switch(widget_state)
{
  default:  /* Fell off the rails--reset and continue */
    widget_state = WIDGET_START;
    /* Fall through */
  case WIDGET_START:
    ...
    break;
  case WIDGET_WHATEVER:
    ...
    break;
}

무효 상태가 기계를 리셋하지 않고 무효 상태로 쉽게 식별할 수 있는 경우 대체 방법:

switch(widget_state)
{
  case WIDGET_IDLE:
    widget_ready = 0;
    widget_hardware_off();
    break;
  case WIDGET_START:
    ...
    break;
  case WIDGET_WHATEVER:
    ...
    break;
  default:
    widget_state = WIDGET_INVALID_STATE;
    /* Fall through */
  case WIDGET_INVALID_STATE:
    widget_ready = 0;
    widget_hardware_off();
    ... do whatever else is necessary to establish a "safe" condition
}

후, 다른 코드로 할 수 .widget_state == WIDGET_INVALID_STATE에러 검출 또는 스테이트 검출 동작이 적절하다고 생각되는 경우는, 모두 제공합니다.들어 되며, 이외의 widget 이 활성화 수 .WIDGET_INVALID_STATE만 아니라WIDGET_IDLE.

또 다른 예를 들어 보겠습니다.이는 "default"가 예기치 않은 경우로 오류를 기록하면서도 합리적인 작업을 수행할 경우 유용합니다.내 코드의 예:

  switch (style)
  {
  default:
    MSPUB_DEBUG_MSG(("Couldn't match dash style, using solid line.\n"));
  case SOLID:
    return Dash(0, RECT_DOT);
  case DASH_SYS:
  {
    Dash ret(shapeLineWidth, dotStyle);
    ret.m_dots.push_back(Dot(1, 3 * shapeLineWidth));
    return ret;
  }
  // more cases follow
  }

파일 쓰기/읽기/읽기를 할 경우 ENUM을 문자열로 변환하거나 문자열을 Enum으로 변환하는 경우가 있습니다.

파일을 수동으로 편집하여 발생하는 오류를 해결하기 위해 값 중 하나를 기본값으로 설정해야 할 경우가 있습니다.

switch(textureMode)
{
case ModeTiled:
default:
    // write to a file "tiled"
    break;

case ModeStretched:
    // write to a file "stretched"
    break;
}

유효하지만 좀 지저분하다.폴스루를 허용하는 것은 매우 지저분한 스파게티 코드를 초래할 수 있기 때문에 일반적으로 좋지 않다고 제안합니다.

이러한 케이스는 여러 개의 스위치 스테이트먼트 또는 작은 함수로 분할하는 것이 거의 확실합니다.

[편집] @Tristopia:예:

Example from UCS-2 to UTF-8 conversion 

r is the destination array, 
wc is the input wchar_t  

switch(utf8_length) 
{ 
    /* Note: code falls through cases! */ 
    case 3: r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
    case 2: r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 
    case 1: r[0] = wc;
}

의도에 대해서는 다음과 같이 기재되어 있으면 (제 생각에는) 더 명확해질 것 같습니다.

if( utf8_length >= 1 )
{
    r[0] = wc;

    if( utf8_length >= 2 )
    {
        r[1] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x0c0; 

        if( utf8_length == 3 )
        {
            r[2] = 0x80 | (wc & 0x3f); wc >>= 6; wc |= 0x800; 
        }
    }
}   

[edit2] @Tristopia:두 번째 예는 아마도 후속 조치를 위한 가장 깨끗한 예입니다.

for(i=0; s[i]; i++)
{
    switch(s[i])
    {
    case '"': 
    case '\'': 
    case '\\': 
        d[dlen++] = '\\'; 
        /* fall through */ 
    default: 
        d[dlen++] = s[i]; 
    } 
}

..개인적으로는 코멘트 인식 기능을 다음과 같이 분할합니다.

bool isComment(char charInQuestion)
{   
    bool charIsComment = false;
    switch(charInQuestion)
    {
    case '"': 
    case '\'': 
    case '\\': 
        charIsComment = true; 
    default: 
        charIsComment = false; 
    } 
    return charIsComment;
}

for(i=0; s[i]; i++)
{
    if( isComment(s[i]) )
    {
        d[dlen++] = '\\'; 
    }
    d[dlen++] = s[i]; 
}

흥미로운 사례가 하나 있는데default이치Arduino Nano, 8월 8일 RAM.로 이 두 코드 과 같습니다.

#if 1 // toggle this 0 or 1
// 3138/265 bytes
uint8_t g_BuiltinLedGlowState = 0; // dropping '= 0' saves nothing
void AdvanceBuiltinLedGlow_3Ph(){
  switch(++g_BuiltinLedGlowState){
  default: 
    g_BuiltinLedGlowState = 0;
    // drop through // break;
  case 0: // bright
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    break;
  case 1: // dim
    pinMode(LED_BUILTIN, INPUT_PULLUP);
    break;
  case 2: // off
    pinMode(LED_BUILTIN, INPUT);
    break;
  }
}
#elif 1
// 3146/265 bytes
uint8_t g_BuiltinLedGlowState = 0; // dropping '= 0' saves nothing
void AdvanceBuiltinLedGlow_3Ph(){
  switch(++g_BuiltinLedGlowState){
  case 1: // bright
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    break;
  case 2: // dim
    pinMode(LED_BUILTIN, INPUT_PULLUP);
    break;
  case 3: // off
    pinMode(LED_BUILTIN, INPUT);
    // drop through // break;
  default: 
    g_BuiltinLedGlowState = 0;
    break;
  }
}
#endif

// the loop function runs over and over again forever
void loop() {
  Serial.println(g_BuiltinLedGlowState, DEC);
  AdvanceBuiltinLedGlow_3Ph();
  delay(1000);
}

언급URL : https://stackoverflow.com/questions/3110088/switch-statement-must-default-be-the-last-case

반응형