2011-06-14 2 views
2

나는 다음과 같은 코드가 정상적인 생각 (와의 malloc/무료 비슷) :malloc/free fopen/fclose가 일치하는지 확인하는 방법은 무엇입니까?

int foo(){ 

    FILE *fp = fopen("test.in", "r"); 

    int i; 

    for(i = 0; i < NUM; i ++){ 
     if(Match(fp, i)){  
      fclose(fp); 
      return i; 
     } 
    } 

    fclose(fp); 
    return 0; 
} 

우리가 fclose(fp)을 볼 수 있듯이 코드에 두 번 나타납니다. 함수 foo에 다른 return 문이 있으면 더 많이 표시됩니다. 그러나 여러 번 번 fclose(fp)을 작성해야한다는 번거 로움이 있습니다. 하나의 해결책은 하나의 함수에 대해 단 하나의 반환입니다. 그러나 여러 차례의 수익이 유용 할 때도 있습니다. 다른 해결책이 있습니까?

추신 : 나는 알고 있듯이, lisp에 매크로 (with-open-file)가 있습니다.

(with-open-file (stream-var open-argument*) 
    body-form*) 

파일을 열거 나 닫을 수 있습니다.

답변

6

, 반환에 대한 잠금 및 기타 자원 알아서해야 많은 기능이 있습니다. 그리고 그들은 일반적으로 함수의 끝 부분에 정리 레이블을 추가하고 조기 반환이 발생할 때마다 goto을 추가합니다. 나는 개인적으로 코드 중복을 피하기 위해이 사용법을 권장하며, 어쩌면 goto의 유일한 정상적인 사용법 일 수있다. (@Charles 펭의 대답에 언급) 내가 고토를 통해 예외 처리에 확장됩니다

int foo(FILE *fp) 
{ 

    int i; 

    for(i = 0; i < NUM; i ++){ 
     if(Match(fp, i)){  
      return i; 
     } 
    } 

    return 0; 
} 

int foo_wrapper(void) 
{ 
    FILE *fp = fopen("test.in", "r"); 
    int out = foo(fp); 
    fclose(fp); 
    return out; 
} 
+0

함수가 매우 큰 경우'goto'를 사용하는 것이 더 좋을 것이라고 생각합니다. – lisper

+1

나는 함수를 매우 크게 만드는 것이 낫다고 생각한다. –

+0

@Bo Persson : 참으로. 실용적인 기능보다 작은 기능을 유지하는 것이 실제로 도움이됩니다. –

7

break의 사용은 종종 도움 :

리눅스 커널의 소스 코드에서
int foo() { 

    FILE *fp = fopen("test.in", "r"); 

    int i, result; 

    result = 0; 
    for(i = 0; i < NUM; i ++){ 
     if(Match(fp, i)){  
      result = i; 
      break; 
     } 
    } 

    fclose(fp); 
    return result; 
} 
+0

변수를 사용하여 상태를 저장하고 이에 따라 프로그램 실행을 지시하는 방법입니다. – thelionroars1337

+0

예, 작동합니다. 코드에 두 개의 루프가있는 경우 내부 루프가 종료됨을 나타 내기 위해 다른 상태를 설정해야하기 때문에 추한 것처럼 보일 것입니다. – lisper

+0

물론, 반드시 : '(I = 0; i가 NUMI <; 내가 ++)에 대한 대한 { (j = 0; j를 dja

2

간접의 추가 레이어를 사용하면 함수에서 출구를 놓치지 마세요 보장 할 수

당신은 그것을 같은 수행

int func(...) 
{ 
    ... 
    f = fopen(...); 
    if (f == NULL) { 
      log("failed opening blah blah..."); 
      goto err; 
    } 
    ... 
    m = malloc(...) 
    if (m == NULL) { 
      log("blah blah..."); 
      goto err_close_f; 
    } 
    ... 
    if (do_something(...) < 0) { 
      log("blah blah..."); 
      goto err_close_f; 
    } 
    ... 
    r = alloc_resource(...) 
    if (r == 0) { 
      log("blah blah..."); 
      goto err_free_m; 
    } 
    ... 
    return 0; 


err_free_m: 
    free(m); 
err_close_f: 
    fclose(f); 
err: 
    return -1; 
} 

이것의 장점은 매우 유지 보수하다는입니다. 자원 획득 및 해제는이 관용구를 사용할 때 다소 대칭적인 모양을 갖습니다. 또한 리소스가 공개되지 않아 과도한 혼란을 피할 수 있습니다. 함수의 오류 처리가 옳은지 확인하는 것은 매우 쉽습니다 (적절한 지점으로 점프하고 이전 레이블이 획득 한 자원을 해제하는지 확인하십시오).

+0

좋은 방법입니다. – lisper

+1

예, 의미있는 이름을 지정하면 모두 설정됩니다. – CAFxX

1

:

+0

감사합니다. 많은 기사는'goto'가 코드에서 더 잘어야한다고 말합니다. 이제'goto'가 제 코드에 나타날 것이라고 생각합니다. :) – lisper

+0

@lisper - 예, 작업에 적합한 도구를 사용하십시오. 개인적으로 나는 항상 함수 범위 (예를 들어,'skip')에 제한된 또 다른 형태의'goto'가 있어야한다고 생각했습니다. – detly

+0

@detly goto 레이블과'goto'가 같은 함수에 있어야한다는 것을 의미합니까? (추신 : 그것은 표준에있었습니다.) – lisper

1

return 문은 함수의 끝이 아닙니다 goto 문과 동일합니다. 비록 여러 함수가 마치 여러 개의 return 문으로 더 단순한 것처럼 보일지 모르지만, 모든 함수에서 단 하나의 종료점을 가진 함수가 유지하기 쉽도록 다양한 코드 기반을 유지하면서 내 경험이었습니다.

관련 문제