이 Q & A를 여러 번 실행했으며보다 포괄적 인 답변을 제공하고자했습니다. 이것에 대해 생각하는 가장 좋은 방법은 호출자에게 오류를 반환 하는 방법 과 반환 하는 것입니다.
어떻게
함수에서 정보를 반환하는 방법은 3 가지가 있습니다.
- 반환 값
- 인수 없음
- 대역 외, 로컬이 아닌 goto (setjmp / longjmp), 파일 또는 전역 범위 변수, 파일 시스템 등이 포함됩니다.
반환 값
반환 값은 단일 객체이지만 임의의 복잡한 것일 수 있습니다. 다음은 오류 반환 함수의 예입니다.
enum error hold_my_beer();
반환 값의 한 가지 이점은 덜 방해적인 오류 처리를 위해 호출 체인을 허용한다는 것입니다.
!hold_my_beer() &&
!hold_my_cigarette() &&
!hold_my_pants() ||
abort();
이것은 가독성에 관한 것이 아니라 그러한 함수 포인터의 배열을 균일 한 방식으로 처리 할 수있게합니다.
인수 없음
인수를 통해 둘 이상의 객체를 통해 더 많은 것을 반환 할 수 있지만 최선의 방법은 총 인수 수를 낮게 유지하는 것이 좋습니다 (예 : <= 4).
void look_ma(enum error *e, char *what_broke);
enum error e;
look_ma(e);
if(e == FURNITURE) {
reorder(what_broke);
} else if(e == SELF) {
tell_doctor(what_broke);
}
대역 외
setjmp ()를 사용하면 장소와 int 값을 처리 할 방법을 정의하고 longjmp ()를 통해 해당 위치로 제어를 전송합니다. C에서 setjmp 및 longjmp의 실제 사용법을 참조하십시오 .
뭐
- 지시자
- 암호
- 목적
- 콜백
지시자
오류 표시기는 문제가 있음을 나타내지 만 언급 된 문제의 특성에 대해서는 아무것도 없습니다.
struct foo *f = foo_init();
if(!f) {
/// handle the absence of foo
}
이것은 함수가 오류 상태를 전달할 수있는 가장 강력한 방법이지만 호출자가 단계적으로 오류에 응답 할 수없는 경우에 적합합니다.
암호
오류 코드는 호출자에게 문제의 특성을 알려주고 적절한 응답을 허용 할 수 있습니다 (위에서). 반환 값이거나 오류 인수 위의 look_ma () 예제와 비슷할 수 있습니다.
목적
오류 개체를 사용하면 임의의 복잡한 문제에 대해 발신자에게 알릴 수 있습니다. 예를 들어, 오류 코드 및 적합한 사람이 읽을 수있는 메시지입니다. 또한 호출자에게 여러 가지 문제가 발생했거나 컬렉션을 처리 할 때 항목 당 오류가 있음을 알릴 수 있습니다.
struct collection friends;
enum error *e = malloc(c.size * sizeof(enum error));
...
ask_for_favor(friends, reason);
for(int i = 0; i < c.size; i++) {
if(reason[i] == NOT_FOUND) find(friends[i]);
}
오류 배열을 사전 할당하는 대신 물론 필요에 따라 동적으로 (재) 할당 할 수도 있습니다.
콜백
콜백은 오류를 처리하는 가장 강력한 방법입니다. 함수에 문제가 발생했을 때 어떤 동작이 발생하는지 알 수 있습니다. 각 함수에 콜백 인수를 추가하거나 다음과 같이 구조체의 인스턴스 당 사용자 정의 UI 만 필요한 경우 :
struct foo {
...
void (error_handler)(char *);
};
void default_error_handler(char *message) {
assert(f);
printf("%s", message);
}
void foo_set_error_handler(struct foo *f, void (*eh)(char *)) {
assert(f);
f->error_handler = eh;
}
struct foo *foo_init() {
struct foo *f = malloc(sizeof(struct foo));
foo_set_error_handler(f, default_error_handler);
return f;
}
struct foo *f = foo_init();
foo_something();
콜백의 한 가지 흥미로운 이점은 여러 번 호출 할 수 있거나 행복한 경로에 오버 헤드가없는 오류가없는 경우에는 전혀 호출 할 수 없다는 것입니다.
그러나 제어의 반전이 있습니다. 호출 코드는 콜백이 호출되었는지 알 수 없습니다. 따라서 표시기를 사용하는 것이 좋습니다.