else 절로 if ... else if 구문을 종료하면 어떤 이점이 있습니까?


136

우리 조직에는 다음과 같은 필수 코딩 규칙이 있습니다 (설명없이).

if… else if 구문은 else 절로 끝나야합니다

예 1 :

if ( x < 0 )
{
   x = 0;
} /* else not needed */

예 2 :

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
}

어떤 에지 케이스가 처리하도록 설계 되었습니까?

그 이유에 대해서도 나에게 관심이있는 것은 예 1 은 필요하지 else않지만 예 2 는 필요하기 때문이다 . 그 이유가 재사용 성과 확장 성 else이라면 두 경우 모두에 사용해야 한다고 생각 합니다.


30
회사에 이유와 이점을 문의하십시오. 언뜻보기에 프로그래머는 그것에 대해 생각하고 "조치가 필요하지 않습니다"라는 주석을 추가해야합니다. Java의 확인 된 예외에 대한 동일한 추론 (그리고 적어도 논쟁의 여지가 있음).
Thilo

32
예 2는 실제로 assert(false, "should never go here")이해가
될만한

2
우리 조직도 비슷한 규칙을 가지고 있지만이 세분화 된 것은 아닙니다. 우리의 경우 목적은 두 가지입니다. 먼저 코드 일관성. 둘째, 느슨한 문자열 / 가독성이 없습니다. 필요하지 않은 경우에도 else를 요구하면 코드화되지 않은 경우에도 코드에 명확성이 추가됩니다. 필요하지 않은 경우에도 앱에서 가능한 모든 결과를 설명하기 위해 과거에 다른 작업이 필요합니다.
LuvnJesus

4
이면 항상 패배 할 수 있습니다 if (x < 0) { x = 0; } else { if (y < 0) { x = 3; }}. 또는 당신은 단지 그러한 규칙을 따를 수 있습니다.
Jim Balter

3
내가 조금 늦게 해요,하지만 여전히 아무도 실수를 잡은 없다 @Thilo 다음 다른 그것은 (수행 할 때 일반 보이는 부작용이 없어야 만한다는, 결코 일어날 것을 아무 표시도 없다 < 0검사)는 주장이 가고 있으므로, 값이 예상 범위에있는 가장 일반적인 경우에 대해 프로그램을 중단시킵니다.
Loduwijk

답변:


148

다른 답변에서 언급했듯이 이는 MISRA-C 코딩 지침에 따른 것입니다. 목적은 미션 크리티컬 프로그래밍에 자주 사용되는 개념 인 방어 프로그래밍입니다.

즉, 모든입니다 if - else if와 반드시 끝 else, 모든 switchA를 반드시 끝 default.

이에 대한 두 가지 이유가 있습니다.

  • 자체 문서화 코드. 당신이를 작성하는 경우 else만은 비워두고 그 의미 : "나는 확실히 시나리오도 고려했다 if이나 else if해당".

    작성하지 else가 의미 : "중 하나를 나는 어느 시나리오로 간주 if하거나 else if해당를, 또는 내가 완전히 고려 잊고 지방 버그가 내 코드에 바로 여기 가능성이있다".

  • 런 어웨이 코드를 중지하십시오. 미션 크리티컬 한 소프트웨어에서는 가능성이 거의없는 강력한 프로그램을 작성해야합니다. 그래서 당신은 같은 코드를 볼 수 있습니다

    if (mybool == TRUE) 
    {
    } 
    else if (mybool == FALSE) 
    {
    }
    else
    {
      // handle error
    }

    이 코드는 PC 프로그래머와 컴퓨터 과학자들에게는 완전히 별개 일 것이지만, "mybool"이 어떤 이유로 든 손상된 경우를 포착하기 때문에 미션 크리티컬 소프트웨어에서는 완벽하게 이해됩니다.

    역사적으로 EMI / 노이즈로 인해 RAM 메모리가 손상 될 우려가 있습니다. 이것은 오늘날 큰 문제가 아닙니다. 코드의 다른 곳에있는 버그로 인해 메모리 손상이 발생할 가능성이 훨씬 높습니다. 잘못된 위치에 대한 포인터, 범위를 벗어난 버그, 스택 오버플로, 런 어웨이 코드 등

    대부분의 경우 구현 단계에서 버그를 작성했을 때 이와 같은 코드가 다시 등장합니다. 디버그 기술로도 사용될 수 있음을 의미합니다. 작성중인 프로그램이 버그를 작성했을 때 알려줍니다.


편집하다

else매번 왜 필요하지 않은지 에 관해서 if:

if-else또는 if-else if-else완전히는 변수가 가질 수있는 가능한 모든 값을 포함한다. 그러나 if모든 가능한 값을 다루기 위해 반드시 명확한 진술이 필요한 것은 아니며 훨씬 더 광범위하게 사용됩니다. 대부분의 경우 특정 조건을 확인하고 충족되지 않으면 아무것도하지 마십시오. 그렇다면 else사건 을 다루기 위해 방어 프로그래밍을 작성하는 것은 의미가 없습니다 .

또한 else매번 빈칸을 썼다면 코드를 완전히 어지럽 힐 것이다 if.

MISRA-C : 2012 15.7은 왜 else필요하지 않은지에 대한 근거를 제시 하지 않고 단지 다음과 같이 말합니다.

참고 : else간단한 if 진술 에는 최종 진술이 필요하지 않습니다 .


6
메모리가 손상되면 검사 코드 자체를 포함하여 mybool 이상의 것을 망칠 것으로 예상됩니다. if/else if/else컴파일 한 결과를 확인하는 다른 블록을 추가하지 않겠 습니까? 그런 다음 이전 검증기를 확인하기 위해 하나 더?
Oleg V. Volkov

49
한숨. 얘들 아, 데스크톱 프로그래밍 이외의 다른 경험이 전혀 없다면, 분명히 경험이없는 것에 대해 모든 것을 알릴 필요가 없습니다. 이것은 방어 프로그래밍에 대해 논의하고 PC 프로그래머가 멈추는 경우 항상 발생합니다. 나는 "이 코드는 PC 프로그래머에게는 완전히 외계인 일 것"이라는 의견을 이유로 추가했습니다. RAM 기반 데스크톱 컴퓨터에서 실행되도록 안전에 중요한 소프트웨어를 프로그래밍하지 마십시오 . 기간. 코드 자체는 ECC 및 / 또는 CRC 체크섬과 함께 플래시 ROM에 상주합니다.
Lundin

6
@Deduplicator 실제로 ( mybool부울이 아닌 유형이 아닌 한 , C가 자체적으로 가져 오기 전과 bool마찬가지로 컴파일러는 추가 정적 분석없이 가정을 수행하지 않습니다). 그리고 '다른 것을 쓰지만 비워두면 "나는 그렇지 않다면 그렇지 않다면 시나리오를 확실히 고려했다"는 주제에 관한 것이다. 나의 첫 반응은 프로그래머가 코드를 입력하는 것을 잊어 버렸다고 가정하는 것이다. else 블록, 그렇지 않으면 왜 비어있는 else 블록이 거기에 앉아 있습니까? // unused의견은 단지 빈 블록, 적절할 것이다.
JAB

5
@JAB 예, else코드가 없으면 블록에 일종의 주석이 포함되어야합니다. 공란 else에 대한 일반적인 관행 은 단일 세미콜론과 주석 else { ; // doesn't matter }입니다. 누군가가 다른 방식으로 들여 쓰기 된 단일 세미 콜론을 자체 줄에 입력하는 이유는 없습니다. 빈 루프에서도 비슷한 방법이 사용됩니다 while(something) { ; // do nothing }. (줄 바꿈으로 코드를 작성하십시오. SO 의견에서는 허용되지 않습니다)
Lundin

5
두 개의 IF를 가진이 샘플 코드는 멀티 스레드 환경의 일반 데스크탑 소프트웨어에서도 다른 방법으로 갈 수 있으므로 mybool의 가치는 다음과 같이 변경 될 수 있습니다.
Iłya Bursov

61

귀사는 MISRA 코딩 지침을 따랐습니다. 이 규칙을 포함하지만 MISRA-C : 2004 의이 지침에는 몇 가지 버전이 있습니다 .

규칙 14.10 (필수) : if if else else 구문은 else 절로 종료해야한다.

이 규칙은 if 문 뒤에 하나 이상의 else if 문이 올 때마다 적용됩니다. 결승전 if다음에는 else 진술이 이어져야 한다 . 간단한 if진술 의 경우 진술을 else 포함시킬 필요는 없습니다. 최종 else 진술에 대한 요구 사항 은 방어 프로그래밍입니다. else문 중 적절한 조치를 취하거나 어떤 조치도 취하지 이유에 대한 적절한 설명을 포함해야한다. 이는 성명서에 최종 default조항 이 있어야한다는 요구 사항과 일치 switch합니다. 예를 들어이 코드는 간단한 if 문입니다.

if ( x < 0 )
{
 log_error(3);
 x = 0;
} /* else not needed */

다음 코드는 if, else if구문을 보여줍니다

if ( x < 0 )
{
 log_error(3);
 x = 0;
}
else if ( y < 0 )
{
 x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
 /* no change in value of x */
}

2004 버전을 대체하고 새 프로젝트에 대한 현재 권장 사항 인 MISRA-C : 2012 에는 동일한 규칙이 있지만 번호는 15.7 입니다.

예 1 : 단일 if 문 프로그래머가 n 개의 조건을 확인하고 단일 작업을 수행해야 할 수도 있습니다.

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}

정기적으로 사용하는 경우에는 항상 작업을 수행 할 필요가 없습니다 if.

예 2 : 여기서 프로그래머는 n 개의 조건을 확인하고 여러 작업을 수행합니다. 일반 사용에서 if..else if처럼 switch기본적 같은 작업을 수행해야 할 수 있습니다. 따라서 elsemisra 표준에 따라 사용법 이 필요합니다

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}
else if(condition_1 || condition_2 || ... condition_n)
{
  //operation_2
}
....
else
{
   //default cause
}

이 출판물의 현재 및 과거 버전은 MISRA 웹 스토어 를 통해 구입할 수 있습니다 ( 를 통해 ).


1
감사합니다. 귀하의 답변은 Misra 규칙의 모든 내용이지만 질문의 일부를 편집 할 때 혼동 될 수 있습니다.
Trevor

2
좋은 대답입니다. 호기심으로, 해당 가이드는 else조항에 도달 할 수 없을 것으로 예상되는 경우 어떻게해야하는지에 대해 말하고 있습니까? (아마도 오류가 발생, 대신 최종 상태를 남겨?)
jpmc26

17
저작권을 위반하는 표절 및 링크에 투표를하겠습니다. 나는 당신의 말과 MISRA의 말이 더 명확 해 지도록 글을 편집 할 것입니다. 처음에는이 답변은 원시 복사 / 붙여 넣기에 불과했습니다.
룬딘

8
@TrieuTheVan : 질문이 목표를 이동 해서는 안됩니다 . 질문 을 게시 하기 전에 완료되었는지 확인하십시오 .
TJ Crowder

1
@ jpmc26 아니요, MISRA의 요점은 엄격한 코드를 제공하는 것이 아니라 안전한 코드를 제공하는 것입니다. 요즘의 컴파일러는 어쨌든 도달 할 수없는 코드를 최적화하므로 단점이 없습니다.
Graham

19

이것은 모든 스위치에서 기본 사례를 요구하는 것과 같습니다.

그렇지 않으면 프로그램의 코드 적용 범위 가 줄어 듭니다 .


리눅스 커널이나 안드로이드 코드를 다른 플랫폼으로 포팅 한 경험에서 여러 번 우리는 뭔가 잘못하고 logcat에서 다음과 같은 오류가 발생합니다.

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
        printk(" \n [function or module name]: this should never happen \n");

        /* It is always good to mention function/module name with the 
           logs. If you end up with "this should never happen" message
           and the same message is used in many places in the software
           it will be hard to track/debug.
        */
}

2
이 곳 __FILE____LINE__매크로는 메시지가 이제까지 인쇄하면 쉽게 찾을 소스 위치를 만들기위한 유용합니다.
Peter Cordes 2016 년

9

약 5 년 전에이 작업을 수행했기 때문에 간단한 설명 만 있습니다.

"널 else( null)" 문 (및 불필요 {..}) 을 포함하는 구문 적 요구 사항은 (대부분의 언어에서) 없으며 "간단한 프로그램"에서는 필요하지 않습니다. 그러나 실제 프로그래머는 "간단한 작은 프로그램"을 작성하지 않으며, 중요하게도 한 번 사용 된 다음 폐기 될 프로그램을 작성하지 않습니다.

if / else를 작성할 때 :

if(something)
  doSomething;
else
  doSomethingElse;

모든 것이 단순 해 보이며 추가 시점조차 거의 보지 못합니다 {..}.

그러나 언젠가는 몇 달이 지난 지금, 다른 프로그래머 (이러한 실수를 저 지르지 않을 것입니다!)는 프로그램을 "강화"하고 설명을 추가해야합니다.

if(something)
  doSomething;
else
  doSomethingIForgot;
  doSomethingElse;

갑자기 다리 doSomethingElse에 있어야한다는 것을 잊어 버렸습니다 else.

그래서 당신은 좋은 작은 프로그래머이며 항상을 사용 {..}합니다. 그러나 당신은 쓴다 :

if(something) {
  if(anotherThing) {
    doSomething;
  }
}

새로운 아이가 자정을 변경할 때까지 모든 것이 좋았습니다.

if(something) {
  if(!notMyThing) {
  if(anotherThing) {
    doSomething;
  }
  else {
    dontDoAnything;  // Because it's not my thing.
  }}
}

그렇습니다. 형식이 잘못 되었으나 프로젝트 코드의 절반이됩니다. "자동 포맷터"는 모든 #ifdef문장에 의해 볼 릭스가됩니다 . 물론 실제 코드는이 장난감 예제보다 훨씬 복잡합니다.

불행히도 (또는 아닙니다), 나는 몇 년 동안 이런 종류의 일을하지 않았으므로 신선한 "실제"예제를 염두에 두지 않습니다.


7

이것은 나중에 참조를 들어, 코드를 더 쉽게 읽을 수 있도록하고 마지막으로 처리 남아있는 경우가 있음을 나중에 검토에, 명확하게하기위한 것입니다 else이다 아무것도 할 그들이 첫눈에 어떻게 든 간과하지 않습니다 그래서, 사례.

이것은 좋은 프로그래밍 관행으로, 코드를 재사용 하고 확장 할 수있게 합니다.


6

이전 답변에 추가하고 부분적으로 모순하고 싶습니다. 식에 대해 생각할 수있는 값의 전체 범위를 포함해야하는 스위치와 같은 방식으로 if-else를 사용하는 것이 일반적이지만 일반적으로 가능한 범위의 조건이 완전히 적용되는 것은 아닙니다. 스위치 구성 자체에 대해서도 마찬가지입니다. 따라서 모든 나머지 값을 포착하고 어쨌든 필요하지 않은 경우 어설 션 보호 장치로 사용할 수있는 기본 절을 사용해야한다는 요구 사항이 있습니다.

질문 자체에는 좋은 반례가 있습니다. 두 번째 조건은 x와 전혀 관련이 없습니다 (스위치 기반 변형보다 유연한 경우 기반 변형을 선호하는 이유입니다). 이 예에서 조건 A가 충족되면 x가 특정 값으로 설정되어야합니다. A가 충족되지 않으면 조건 B가 테스트됩니다. 충족되면 x는 다른 값을 받아야합니다. A와 B가 모두 충족되지 않으면 x는 변경되지 않습니다.

여기서 우리는 독자에 대한 프로그래머의 의도에 대해 주석을 달기 위해 비어있는 else 브랜치를 사용해야 함을 알 수 있습니다.

반면에, 가장 최근의 가장 최근의 if 문에 else 절이 왜 필요한지 알 수 없습니다. C에서는 'else if'와 같은 것이 없습니다. if와 else 만 있습니다. 대신, MISRA에 따르면, 구조는 공식적으로 이런 식으로 들여 쓰기해야합니다 (그리고 여는 중괄호를 자체 줄에 넣어야하지만 좋아하지는 않습니다).

if (A) {
    // do something
}
else {
    if (B) {
        // do something else (no pun intended)
    }
    else {
        // don't do anything here
    }
}

MISRA가 모든 브랜치 주위에 중괄호를 넣으라고 요청하면 "if ... else if constructs"라고 언급함으로써 모순됩니다.

중첩의 다른 나무, 경우에 사람은 추함을 상상할 수있는 보조 노트에 여기를 참조하십시오 . 이제이 구조를 어느 곳에서나 임의로 확장 할 수 있다고 상상해보십시오. 그런 다음 마지막에 else 절을 ​​요청하지만 다른 곳에서는 그렇지 않습니다.

if (A) {
    if (B) {
        // do something
    }
    // you could to something here
}
else {
    // or here
    if (B) { // or C?
        // do something else (no pun intended)
    }
    else {
        // don't do anything here, if you don't want to
    }
    // what if I wanted to do something here? I need brackets for that.
}

따라서 MISRA 지침을 개발 한 사람들은 의도가 있다면 스위치 형 if-else를 가지고 있다고 확신합니다.

결국, "if ... else if construct"의 의미를 정확하게 정의하는 것은 그들이 내려온 것입니다.


5

기본적인 이유는 아마도 코드 커버리지와 암시 적 다른 것입니다. 조건이 true가 아닌 경우 코드는 어떻게 작동합니까? 실제 테스트의 경우 false 조건으로 테스트했는지 확인할 수있는 방법이 필요합니다. 모든 테스트 사례가 if 절을 거치면 테스트하지 않은 조건으로 인해 실제 코드에서 문제가 발생할 수 있습니다.

그러나 세금 환급과 같이 일부 조건은 예 1과 동일 할 수 있습니다. "결과가 0보다 작 으면 0을 입력하십시오." 여전히 조건이 거짓 인 테스트가 필요합니다.


5

논리적으로 모든 테스트는 두 가지를 의미합니다. 그것이 사실이라면 무엇을하고, 그것이 거짓이라면 무엇을합니까?

어느 브랜치에 기능이없는 경우 기능이 필요하지 않은 이유에 대한 의견을 추가하는 것이 합리적입니다.

이것은 다음 유지 보수 프로그래머에게 도움이 될 수 있습니다. 코드가 올바른지 판단하기 위해 너무 멀리 검색하지 않아도됩니다. 당신은 코끼리Prehunt 할 수 있습니다 .

개인적으로, 다른 경우를보고 평가하도록 강요 할 때 도움이됩니다. 불가능한 조건 일 수 있습니다.이 경우 계약을 위반하면 예외가 발생할 수 있습니다. 양성일 수 있으며,이 경우 주석이 충분할 수 있습니다.

귀하의 마일리지가 다를 수 있습니다.


4

대부분의 경우 단일 if진술 이있을 때 아마도 다음과 같은 이유 중 하나 일 것입니다.

  • 기능 가드 점검
  • 초기화 옵션
  • 선택적 처리 지점

void print (char * text)
{
    if (text == null) return; // guard check

    printf(text);
}

그러나 할 때 if .. else if아마도 다음과 같은 이유 중 하나 일 것입니다.

  • 다이나믹 스위치 케이스
  • 가공 포크
  • 처리 매개 변수 처리

그리고 if .. else if모든 가능성을 다루는 경우, 마지막 경우 if (...)가 필요하지 않은 경우, 그 시점에서 가능한 값은 해당 조건에서 다루는 값이기 때문에 제거 할 수 있습니다.

int absolute_value (int n)
{
    if (n == 0)
    {
        return 0;
    }
    else if (n > 0)
    {
        return n;
    }
    else /* if (n < 0) */ // redundant check
    {
        return (n * (-1));
    }
}

그리고 대부분의 이유로, 귀하의 카테고리에 해당하지 않는 항목이있을 수 있으므로 if .. else if최종 else조항에서 처리 해야 할 필요가 있습니다 . 처리는 비즈니스 수준 절차, 사용자 알림, 내부 오류 메커니즘, ..기타.

#DEFINE SQRT_TWO   1.41421356237309504880
#DEFINE SQRT_THREE 1.73205080756887729352
#DEFINE SQRT_FIVE  2.23606797749978969641

double square_root (int n)
{
         if (n  > 5)   return sqrt((double)n);
    else if (n == 5)   return SQRT_FIVE;
    else if (n == 4)   return 2.0;
    else if (n == 3)   return SQRT_THREE;
    else if (n == 2)   return SQRT_TWO;
    else if (n == 1)   return 1.0;
    else if (n == 0)   return 0.0;
    else               return sqrt(-1); // error handling
}

이 마지막 else절은 Javaand C++와 같은 언어의 다른 몇 가지와 매우 유사합니다 .

  • default switch 문의 사례
  • catch(...)모든 특정 catch블록 뒤에 오는
  • finally try-catch 절에서

2

우리의 소프트웨어는 미션 크리티컬 한 것은 아니지만 방어 적 프로그래밍 때문에이 규칙을 사용하기로 결정했습니다. 우리는 이론적으로 도달 할 수없는 코드 (스위치 + if-else)에 예외를 추가했습니다. 예를 들어, 새로운 유형이 추가 된 경우 소프트웨어가 빠르게 실패하여 1 ~ 2 개의 if-else 또는 스위치를 변경하는 것을 잊었을 때 많은 시간을 절약했습니다. 보너스로 문제를 쉽게 찾을 수있었습니다.


2

글쎄, 내 예는 정의되지 않은 행동과 관련이 있지만 때로는 어떤 사람들은 공상하려고 노력하고 열심히 실패합니다.

int a = 0;
bool b = true;
uint8_t* bPtr = (uint8_t*)&b;
*bPtr = 0xCC;
if(b == true)
{
    a += 3;
}
else if(b == false)
{
    a += 5;
}
else
{
    exit(3);
}

당신은 아마있을 것으로 예상 결코 bool되지 않는 true않으며 false, 그러나 그것은 발생할 수 있습니다. 개인적으로 나는 이것이 멋진 무언가를하기로 결정한 사람에 의해 발생하는 문제라고 생각하지만 추가 else진술은 더 이상의 문제를 예방할 수 있습니다.


1

현재 PHP로 작업 중입니다. 등록 양식 및 로그인 양식 작성 나는 순전히 if와 else를 사용하고 있습니다. 불필요하다면 다른 것은 없습니다.

사용자가 제출 버튼을 클릭하면 다음 if 문으로 이동합니다. username이 'X'자보다 적은 경우 경고합니다. 성공하면 암호 길이 등을 확인하십시오.

모든 추가 코드를 확인하기 위해 서버로드 시간의 안정성을 해제 할 수있는 경우 다른 코드와 같은 추가 코드가 필요하지 않습니다.

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