Short-circuit evaluation?

A && BA || B 등에서는 A의 결과에 따라 B가 평가되지 않을 수도 있습니다.

예를 들어 true || printf("Hello world!\\n")printf는 실행되지 않습니다.

이런 것을 short-circuit evaluation이라고 합니다.

Exception, throw, try~catch

C++, Java 등 다양한 언어에서는 try , catch를 사용해 예외를 처리할 수 있습니다.

해당 예외에 대한 Exception 객체를 throw하면 가까운 catch에서 처리할 수 있습니다.

int doSomethingMayFail(int a, int b) {
    return a / b; // 예외가 발생할 수 있는 부분
}
int doSomething(int a, int b) {
    try {
        return doSomethingMayFail(a, b); // 이 try 블록 안에서 예외가 발생하면
    } catch(Exception e) {
        System.out.println("오류 발생!");
        return 0; // 해당 예외에 대한 Exception을 catch에서 처리할 수 있음!
    }
}
void main() {
    System.out.println(doSomething(100, 0)); // 출력 결과는 0
}

하지만 C에는 throw, try, catch나 그런 비슷한 게 없죠.

throw, try, catch를 따라해보자!

펼치면 자세한 내용을 확인할 수 있습니다.

별로... 알고싶지 않은 내용일 수 있어요. 벌써 코드가 개판이 됐네요

Short-circuit evaluation을 활용하자!

위의 예시에서는 예외가 발생한 경우 catch로 넘어갈 때 if를 사용했습니다.

하지만 short-circuit evaluation을 활용한다면 정말 간단해집니다!

int do_something_with_multiple_throwable_functions(int base, int *out_result)
{
    t_exception *exception;
    int         seven;
    int         fourteen;
    int         twenty_one;
    int         ft;

    if ( // 예외가 발생하면 다음으로 진행하지 않음!
        get_lucky_seven(base, &exception, &seven)
        || get_double(seven, &exception, &fourteen)
        || sum(seven, fourteen, &exception, &twenty_one)
        || get_double(twenty_one, &exception, &ft))
    { // 한 번이라도 예외가 발생하면 여기에서 처리!
        ft_put_line_fd(d.value.exception, STDERR_FILENO);
        return (42);
    }
    return (ft);
}

대신 이렇게 된다면 예외가 발생할 수 있는 부분의 코드를 조금 수정해야 합니다.

결과를 리턴하는 것이 아니라 성공이면 0, 예외가 발생하면 1을 리턴해야 합니다.

그리고 결과를 넣을 곳의 주소와 exception의 주소도 받아야 합니다.

t_err   ft_malloc(size_t size, void **out, t_exception *exception)
{
    void *const result = malloc(size);

    if (!result)
    {
        *exception = "OUT OF MEMORY!";
        return (true);
    }
    *out = result;
    return (false);
}

Stack Trace를 추가하자

열심히 준비했으나, 순수 C로 할 만 한 짓은 아닌 것 같아서 지웠습니다.

개발 과정 중에는 그냥 디버거 쓰면 디버거가 알아서 이것보다 훨씬 더 잘 해 줍니다.

Untitled

Error on main.c:5: Hello world!
|       test
stacktrace:
        At main.c:12
Error on main.c:5: Hello world!
|       test
stacktrace:
        At main.c:21 - test...
        |       This is optional message, even multiline is OK also!
        |       xD

실제 C++의 throw랑 비교하면?

C++의 throw가 더 빠릅니다.

이 방식의 예외 처리는 함수를 하나하나 벗어나면서 자원 해제 등의 적당한 처리를 합니다.

C++의 throwcatch로 한 번에 점프하면서 심지어 적당한 처리까지 빼놓지 않습니다...

하지만 그런 컴파일러의 마법같은 최적화를 제외하면 대충 비슷하게 동작합니다 🙂