A && B
나 A || B
등에서는 A
의 결과에 따라 B
가 평가되지 않을 수도 있습니다.
예를 들어 true || printf("Hello world!\\n")
의 printf
는 실행되지 않습니다.
이런 것을 short-circuit evaluation이라고 합니다.
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
나 그런 비슷한 게 없죠.
펼치면 자세한 내용을 확인할 수 있습니다.
별로... 알고싶지 않은 내용일 수 있어요. 벌써 코드가 개판이 됐네요
위의 예시에서는 예외가 발생한 경우 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);
}
열심히 준비했으나, 순수 C로 할 만 한 짓은 아닌 것 같아서 지웠습니다.
개발 과정 중에는 그냥 디버거 쓰면 디버거가 알아서 이것보다 훨씬 더 잘 해 줍니다.
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
는 catch
로 한 번에 점프하면서 심지어 적당한 처리까지 빼놓지 않습니다...
하지만 그런 컴파일러의 마법같은 최적화를 제외하면 대충 비슷하게 동작합니다 🙂