There’s a pair of C functions that I feel are underused, namely setjmp(3)
, and longjmp(3)
. With them, you can fake exceptions in C, implement coroutines, and much more.
The two functions work as a pair: setjmp
saves the current stack context in a jmp_buf
; longjmp
can then revert back to the saved state. Ideally, a jmp_buf
is a pointer to a position in the stack; setjmp
saves the current position, and longjmp
jumps back to a saved position. All of this is a bit more complicated in real life, and is very implementation specific.
For example, here’s a couple of coroutines that work through the Collatz Conjecture. One of the functions divides even numbers by two, while the other multiplies odd numbers by three and adds one.
#include <stdio.h>
#include <setjmp.h>
void even(int);
void odd(int);
int main(int argc, char *argv[]) {
even(7);
return 0;
}
jmp_buf even_task, odd_task;
void even(int n) {
int aux;
if (!(aux = setjmp(even_task))) {
odd(n);
} else {
n = aux;
}
while (n > 1) {
while (n % 2 == 0) {
printf("Even! %3d/2 =\n", n);
n /= 2;
}
if (!(aux = setjmp(even_task))) {
longjmp(odd_task, n);
} else {
n = aux;
}
}
printf("Done! 1\n");
}
void odd(int n) {
while (n > 1) {
if (n % 2 == 1) {
printf("Odd! %3d*3+1 =\n", n);
n = 3 * n + 1;
}
int aux;
if (!(aux = setjmp(odd_task))) {
longjmp(even_task, n);
} else {
n = aux;
}
}
}
I’m not particularly happy with the lack of symmetry between odd
and even
. Here’s a forkable gist of the above, if anyone wants to have a go at improving it.