codememo

브레이스가 없는 스위치 문을 사용하는 유용한 사례가 있습니까?

tipmemo 2023. 6. 17. 09:24
반응형

브레이스가 없는 스위치 문을 사용하는 유용한 사례가 있습니까?

H&S5에서 저는 교정기를 사용하지 않는 "가장 기괴한" 스위치 문구(8.7.1, 페이지 277)를 마주쳤습니다.
다음은 샘플입니다.

switch (x)
    default:
    if (prime(x))
        case 2: case 3: case 5: case 7:
            process_prime(x);
    else
        case 4: case 6: case 8: case 9: case 10:
            process_composite(x);

그 아이디어는 비용 부담을 피하기 위한 것으로 보입니다.prime(x)가장 일반적인 소수의 경우.

제가 그 문장을 보았을 때, 저는 브레이스가 빠진 것에 대해 혼란스러웠지만, 공식 문법(C1X 사전 표준, 6.8.4, 페이지 147)을 확인했을 때 구문은 정확했습니다: 스위치 문장은 스위치 식과 닫는 괄호 뒤에 문장이 있습니다.

하지만 프로그래밍 연습에서 저는 다시는 그렇게 이상한 스위치 문을 마주치지 않았습니다(그리고 제가 책임져야 하는 코드에서 어떤 것도 보고 싶지 않습니다). 하지만 저는 다음과 같은 의문을 갖기 시작했습니다.

교정기를 사용하지 않고 여전히 의미가 있는 스위치 표현을 알고 있는 사람이 있을까요?뿐만 아니라.switch (i);(이것은 합법적이지만 NOP), 그러나 적어도 두 개 이상의 사례 라벨을 사용하는 것은 어떤 유용한 목적을 가지고 있습니까?

a 로매에 사용는하경우를조구제서어크▁if경우는▁struct하▁a▁control▁you용ures▁macrosswitchif이 없기 합니다.else문제.

#define DEBUG_PRINT(...) switch (!debug_mode) case 0: fprintf(__VA_ARGS__)

따라서 해당 매크로의 사용자가 이를 추가 조건으로 지정해도 놀랄 일이 없습니다.

if (unclear) DEBUG_PRINT(stderr, "This is really %unclear\n", unclear);
else {
 // do something reasonable here
}

이러한 디버그 매크로는 항상 컴파일되고 나중에 최적화된다는 이점이 있습니다.따라서 디버그 코드는 프로그램의 모든 라이브 시간 동안 유효해야 합니다.

또한 여기서 관찰하는 것은 중요합니다.switch사하지않을 {} 않으면if/else예도 통하지 않을 것입니다. 것은 될 수 .if/else,(void)0그리고.do/while트릭) 하지만 이것이 제가 아는 것 중 가장 편리합니다.

그리고 저를 오해하지 마세요. 저는 모든 사람들이 매크로 내부의 제어 구조를 사용해야 한다고 말하지 않습니다. 여러분은 확실히 여러분이 무엇을 하고 있는지 알아야 합니다.하지만 그것이 정당화되는 상황들이 있습니다.

여기 1972년 데니스 리치가 최초의 C 컴파일러 작업 중에 쓴 예가 있습니다.방금 연결한 페이지 하단에 링크된 c02.c 모듈은 다음을 포함합니다.

easystmt()
{
    extern peeksym, peekc, cval;

    if((peeksym=symbol())==20)  /* name */
        return(peekc!=':');  /* not label */
    if (peeksym==19) {      /* keyword */
        switch(cval)
        case 10:    /* goto */
        case 11:    /* return */
        case 17:    /* break */
        case 18:    /* continue */
            return(1);
        return(0);
    }
    return(peeksym!=2);     /* { */
}

1972년 코드를 읽어보면 데니스가 스위치 성명서의 팬이었음이 분명합니다. 그는 그것들을 꽤 많이 사용했습니다.거의 모든 것이 부분적으로 다른 데이터 유형 가능성이 부족하기 때문에 인트로 인코딩되었다는 점을 고려하면 그리 놀라운 일은 아닙니다.그의 컴파일러 구현은 언어에 구조를 추가하는 중이었기 때문에 그 단계에서 구조를 사용하지 않았습니다.동적 파견, vtables 및 다형성은 아직 멀었습니다.저는 이것에 대한 참조를 찾으려고 노력했지만 찾지 못했습니다. 하지만 제가 정확히 기억한다면 Dennis는 스위치 문을 "발명"하거나 적어도 C에서 그들이 취하는 형태로 이어지는 기여한 아이디어를 그의 언어에 대한 최고 또는 자랑스러운 추가물하나로 간주합니다.

브레이스를 생략할 수 있는 기능은 스위치 문을 공식적으로 다음과 유사하게 만듭니다.if,for,do그리고.while문법을 단순화하고 통일하는 데 도움이 되는 진술.이러한 것들이 정의되어 있는 C 문법의 선택-문장 및 반복-문장 제작을 참조하십시오(예: 커니헌과 리치의 부록 A13, 내 사본의 236-237페이지).

분명히 교정기를 항상 추가할 수 있지만 이와 같은 간단한 예에서는 무거워 보일 수 있습니다.이 예제는 분리형 if 문으로 코딩될 수 있지만 Dennis가 스위치에 대해 가지고 있던 아이디어 중 하나는 컴파일러가 관련된 특정 상수를 기반으로 분기 로직의 구현을 최적화할 수 있는 기회를 더 명확하게 제공하고 있다는 것입니다.

다른 사건을 생각해 봤어요

루프의 반복 횟수를 나타내는 부호 없는 문자 유형의 카운터가 있다고 가정합니다. 하지만 카운터가 0이면 루프를 256번 통과해야 합니다.내 생각이 맞다면, 당신은 이것을 다음과 같이 코딩할 수 있습니다.

uint8_t counter;
/* counter will get its value here somewhere */
switch (counter)
    default:
        while (0 < counter)
        {
            case 0:
                /* Perform action */
                counter--;
        }

물론 이는 0x00의 언더플로우가 부호 없는 문자에 대해 0xFF를 생성한다고 가정합니다.하지만 모든 환경에 적용됩니다. 비록 PC Lint가 불평을 하겠지만...그리고 네, 교정기가 포함되어 있습니다. 하지만 그냥.while을 위한 것이 아닌switch당신이 더 잘 아는 것이 있다면, 제게 들려주세요!

제가 이렇게 프로그래밍을 할까요?절대로! ...글쎄요, 작은 8비트 프로세서로 할 수도 있어요! :-)

섹션 6.8.4.2 스위치 설명은 다음과 같습니다.

스위치 문을 사용하면 제어 식의 값과 스위치 본체의 기본 레이블 및 대/소문자 레이블 값에 따라 컨트롤이 스위치 본체인 문으로 이동하거나 문으로 이동하거나 스위치 본체의 문을 통과할 수 있습니다.케이스 또는 기본 레이블은 가장 가까운 동봉 스위치 문 내에서만 액세스할 수 있습니다.

스위치-본체가장 가까운 주변 스위치-문이라는 용어는 중괄호를 필요로 하지 않는 것 같습니다.그래서 당신이 옳습니다. 이상하게 보이지만 합법적입니다.(전에 본 적이 없는 것)

실제로 스위치는 가독성을 위해 (더프의 장치에서도) 브레이스와 함께 사용됩니다.그리고 교정기를 추가하는 것은 해롭지 않습니다.

언급URL : https://stackoverflow.com/questions/8118009/is-there-a-useful-case-using-a-switch-statement-without-braces

반응형