반환이있는 Switch 문 — 코드 정확성


91

대략 다음과 같은 구조의 C 코드가 있다고 가정 해 보겠습니다.

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

이제 분명히 breaks는 코드가 올바르게 실행되는 데 필요하지 않지만 내가 거기에 넣지 않으면 나쁜 습관처럼 보입니다.

어떻게 생각해? 제거해도 괜찮습니까? 아니면 "정확성"을 높이기 위해 보관 하시겠습니까?

답변:


139

break문을 제거하십시오 . 필요하지 않으며 일부 컴파일러는 "연결할 수없는 코드" 경고를 표시합니다.


2
동일은 같은 다른 무조건 제어 점프 문에 적용 continue하거나 goto이의 장소에 사용하는 관용적이다 - break.
caf

32

나는 완전히 다른 방법을 취할 것입니다. 방법 / 기능 중간에 반환하지 마십시오. 대신 반환 값을 지역 변수에 넣고 끝에 보냅니다.

개인적으로 다음 내용이 더 읽기 쉽습니다.

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;

24
"One Exit"철학은 C에서 의미가 있습니다. C에서는 사물이 올바르게 정리되었는지 확인해야합니다. C ++에서 예외로 인해 언제든지 함수에서 빠져 나올 수 있다는 점을 고려할 때 하나의 종료 철학은 C ++에서 실제로 유용하지 않습니다.
Billy ONeal 2010-06-17

29
이론적으로 이것은 좋은 생각이지만 가독성을 방해 할 수있는 추가 제어 블록이 자주 필요합니다.
mikerobi 2010-06-17

8
내가 이런 식으로 일하는 주된 이유는 더 긴 함수에서 코드를 스캔 할 때 종료 벡터를 놓치기가 매우 쉽기 때문입니다. 그러나 출구가 항상 끝에 있으면 무슨 일이 일어나고 있는지 빨리 파악하는 것이 더 쉽습니다.
NotMe

7
글쎄, 코드 중간에 블록을 반환하면 GOTO 남용을 상기시킵니다.
NotMe

5
@Chris : 더 긴 기능에서는 전적으로 동의하지만 일반적으로 더 큰 문제를 말하므로 리팩토링하십시오. 대부분의 경우 스위치에서 반환되는 사소한 기능이며 어떤 일이 발생해야하는지 매우 명확하므로 추가 변수를 추적하는 데 두뇌 능력을 낭비하지 마십시오.
Stephen

8

개인적으로 나는 반품을 제거하고 휴식을 유지합니다. 변수에 값을 할당하기 위해 switch 문을 사용합니다. 그런 다음 switch 문 뒤에 해당 변수를 반환합니다.

이것이 논쟁의 여지가 있지만, 좋은 디자인과 캡슐화는 한 가지 방법과 한 가지 방법을 의미한다고 항상 느꼈습니다. 논리를 보장하는 것이 훨씬 더 쉽고 함수의 순환 적 복잡성을 기반으로하는 정리 코드를 실수로 놓치는 일이 없습니다.

한 가지 예외 : 리소스를 획득하기 전에 함수 시작 부분에서 잘못된 매개 변수가 감지되면 일찍 반환해도 괜찮습니다.


이 특정에 좋을 수도 switch있지만 반드시 일반적으로 최선은 아닙니다. 음, 함수 내부의 switch 문이 특정 경우에만 유효한 500 줄의 코드 앞에 있다고 가정 해 봅시다 true. 실행할 필요가없는 경우에 대해 모든 추가 코드를 실행하는 이유는 무엇입니까? 그 s를 위해 return내부에있는 것이 더 낫지 않습니까? switchcase
Fr0zenFyr

6

휴식 시간 유지-휴식 시간이 이미있는 경우 나중에 코드를 편집 할 때 문제가 발생할 가능성이 적습니다.

그렇긴하지만 (나를 포함하여) 많은 사람들이 함수 중간에서 돌아 오는 것은 나쁜 습관이라고 생각합니다. 이상적으로 함수에는 하나의 진입 점과 하나의 종료 점이 있어야합니다.


5

그들을 제거하십시오. case명령문에서 반환하는 것은 관용적 이며 그렇지 않으면 "도달 할 수없는 코드"잡음입니다.


5

나는 그들을 제거 할 것이다. 내 책에서, 그와 같은 데드 코드는 실수로 간주되어야합니다. 왜냐하면 이중 테이크를하고 스스로에게 "어떻게 그 라인을 실행할 수 있을까요?"


4

나는 보통 그들없이 코드를 작성합니다. IMO, 데드 코드는 엉성함 및 / 또는 이해 부족을 나타내는 경향이 있습니다.

물론 다음과 같은 것도 고려할 것입니다.

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

편집 : 편집 된 게시물을 사용해도이 일반적인 아이디어는 잘 작동 할 수 있습니다.

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

어떤 시점에서, 특히 입력 값이 희소 한 경우 (예 : 1, 100, 1000 및 10000) 대신 희소 배열이 필요합니다. 트리 또는 맵으로 구현할 수 있습니다 (물론이 경우에도 스위치가 여전히 작동합니다).


이 솔루션이 제대로 작동하지 않는 이유를 반영하기 위해 게시물을 편집했습니다.
houbysoft

@your edit : 예,하지만 더 많은 메모리가 필요합니다. IMHO 스위치는 가장 간단한 방법입니다. 이것이 제가 원하는 작은 기능 (스위치 만 수행합니다)입니다.
houbysoft 2010-06-17

3
@houbysoft : 추가 메모리가 필요하다는 결론을 내리기 전에주의 깊게 살펴보십시오. 일반적인 컴파일러에서 "foo"를 두 번 (예를 들어) 사용하면 데이터를 복제하지 않고 단일 데이터 블록에 대한 두 개의 포인터를 사용합니다. 더 짧은 코드를 기대할 수도 있습니다. 당신이 있지 않는 한 많은 반복 값을, 종종 전체 메모리를 저장합니다.
Jerry Coffin

진실. 값 목록이 매우 길고 스위치가 더 멋져 보이기 때문에 여전히 내 솔루션을 고수 할 것입니다.
houbysoft

1
실제로 이와 같은 문제에 대한보다 우아하고 효율적인 대답은 스위치 값이 인접하고 데이터 유형이 동종 일 때 스위치를 아예 피하는 배열을 사용하는 것입니다.
Dwayne Robinson

2

나는 그것들을 제거하고 default : branch를 정의한다고 말할 것입니다.


합리적인 기본값이없는 경우 기본값을 정의하지 않아야합니다.
Billy ONeal 2010-06-17

하나가 있고, 하나를 정의했습니다. 질문에 넣지 않고 지금 편집했습니다.
houbysoft 2010-06-17

2

배열을 갖는 것이 더 낫지 않을까요?

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

그리고 return arr[something]; ?

일반적으로 관행에 관한 것이라면 break진술을 스위치에 유지해야 합니다. return앞으로 진술이 필요하지 않은 경우 다음 단계로 넘어갈 가능성이 줄어 듭니다 case.


이 솔루션이 제대로 작동하지 않는 이유를 반영하기 위해 게시물을 편집했습니다.
houbysoft

2

"정확성"의 경우 단일 진입, 단일 출구 블록이 좋은 생각입니다. 적어도 그들은 제가 컴퓨터 공학 학위를 받았을 때였습니다. 그래서 아마도 변수를 선언하고 스위치에 할당하고 함수의 끝에서 한 번 반환합니다.


2

어떻게 생각해? 제거해도 괜찮습니까? 아니면 "정확성"을 높이기 위해 보관 하시겠습니까?

그들을 제거하는 것이 좋습니다. 사용은 return 이다 정확하게 시나리오 break사용할 수 없습니다.


1

흥미 롭군. 이 답변의 대부분은 중복 break진술이 불필요한 혼란 이라는 데 동의하는 것 같습니다 . 반면에 저는 break스위치 의 진술을 사건의 '종결' 이라고 읽었습니다 . case끝나지 않는 블록은 break버그를 통해 잠재적으로 떨어질 때 나에게 튀어 나오는 경향이 있습니다.

내가있을 때 그것이 얼마나 그 것이 아니 어서, return대신의 break,하지만 내 눈을 '읽기'스위치의 경우 블록, 그래서 나는 개인적으로 각각 것을 선호하는 방법의 case과 쌍 break. 그러나 많은 컴파일러는 불필요한 / 접근 불가능한 break이후 에 대해 불평 return하며, 어쨌든 나는 소수 인 것 같습니다.

따라서 break다음을 제거 하십시오 return.

주의 :이 모든 것은 단일 진입 / 퇴장 규칙을 위반하는 것이 좋은 생각인지 아닌지를 무시하는 것입니다. 그 정도면 안타깝게도 상황에 따라 달라진다는 의견이 있습니다 ...


0

나는 그들을 제거하라고 말한다. 코드를 읽을 수 없어서 '안전한면에 있기 위해'휴식을 취해야하는 경우 코딩 스타일을 재고해야합니다. :)

또한 나는 항상 switch 문에서 break와 return을 혼합하지 않고 그중 하나를 고수하는 것을 선호했습니다.


0

나는 개인적으로 breaks 를 잃는 경향이 있습니다. 이 습관의 원인 중 하나는 Windows 앱용 프로그래밍 창 프로 시저에서 비롯된 것 같습니다.

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

개인적으로이 접근 방식은 각 핸들러에 의해 설정된 반환 변수를 선언 한 다음 마지막에 반환하는 것보다 훨씬 간단하고 간결하며 유연합니다. 이 접근 방식을 감안할 때 breaks는 중복되므로 이동해야합니다. 유용한 목적 (구문 적으로 또는 IMO 시각적으로)을 제공하지 않고 코드 만 부풀립니다.


0

나는 * break * s가 목적을 위해 존재 . 프로그래밍의 '이념'을 유지하는 것입니다. 논리적 일관성없이 코드를 '프로그램'하려면 지금은 읽을 수 있지만 내일 시도해보십시오. 상사에게 설명해보세요. Windows 3030에서 실행 해보십시오.

Bleah, 아이디어는 매우 간단합니다.


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_assembly;
   LONG assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/ * 사소한 질문입니다. 위의 내용을 읽으면서 커피를 얼마나 마셨습니까? IT 는 때때로 시스템을 망가 뜨립니다 * /


0

한 지점에서 종료 코드. 이는 코드에 대한 더 나은 가독성을 제공합니다. 그 사이에 return 문 (다중 종료)을 추가하면 디버깅이 어려워집니다.


0

"조회"유형의 코드가있는 경우 자체적으로 메서드에 switch-case 절을 ​​패키징 할 수 있습니다.

재미를 위해 개발중인 "취미"시스템에이 중 몇 가지가 있습니다.

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(예. GURPS 공간입니다 ...)

나는 당신이 대부분의 경우 메서드에서 하나 이상의 반환을 피해야한다는 다른 사람들의 의견에 동의하며 이것이 배열이나 다른 것으로 더 잘 구현되었을 수도 있음을 알고 있습니다. 방금 switch-case-return이 위의 것과 같이 입력과 출력 사이에 1-1 상관 관계가있는 룩업 테이블과 매우 쉽게 일치하는 것으로 나타났습니다. "비즈니스"도) : D

반면에 case-clause가 더 복잡하거나 switch-statement 이후에 어떤 일이 발생하면 return을 사용하지 않는 것이 좋습니다. 대신 스위치에 변수를 설정하고 break로 끝내고 return 끝에있는 변수의 값.

(... 세 번째? 손으로 ... 스위치를 항상 자체 메서드로 리팩터링 할 수 있습니다 ... 성능에 영향을 미칠지 의심스럽고 최신 컴파일러가이를 인식 할 수 있다고해도 놀라지 않을 것입니다. 인라인 될 수있는 것 ...)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.