This is a simple example:
// in some header: #define OK 0 #define NOT_OK 1 int doCalculations() { int rc = 0; rc = calcSomething(); if ( rc != OK ) { printf("function calcSomething had an error.\n"); return NOT_OK; } rc = calcSomethingElse(); if ( rc != OK ) { printf("function calcSomethingElse had an error.\n"); return NOT_OK; } return OK; }The problem here is that it is hard to follow the flow of the business logic since error handling is happening on the same stage. To gain better readability I started to split the business logic and the error handling inside the function using goto:
// in some header: #define OK 0 #define NOT_OK 1 int doCalculations() { int rc = 0; rc = calcSomething(); if ( rc != OK ) goto error_calcSomething; rc = calcSomethingElse(); if ( rc != OK ) goto error_calcSomethingElse; return OK; // error handling error_calcSomething: printf("function calcSomething had an error.\n"); return NOT_OK; error_calcSomethingElse: printf("function calcSomethingElse had an error.\n"); return NOT_OK; }Now the upper part of the function deals mostly with the business logic (you can't get rid of the return code checking totally), the lower part is purly used for error handling. This technique is quite popular, I also spotted it inside the Linux kernel sources.
To my defense I need to state: I only use the evil goto for that one purpose: error handling and freeing of locally allocated heap data - nothing else.
By the way: An alternative way to print a backtrace is provided by the glibc with the backtrace function. However, this is not part of the ANSI C standard - if this is important for you.
Keine Kommentare:
Kommentar veröffentlichen