Brainfuck interpreter (with emphasis on robustness)
Deficiencies? I don't really see any. Improvements? Maybe :)


You don't handle at all the return values of putchar, getchar and fflush. The Wikipedia article has some hints about how different implementations handle an EOF from the user input. Yours works as well, but is this really what you want?
In build_jump_table, the switch used to check whether *c is a [ or a ] seems a bit overkill. It would probably be easier to get away with a simple if .. else statement.
That's highly speculative, but I guess that if you replace the characters &lt;, &gt;, -, +, ., ,, [ and ] by values ranging from 0 to 7, or at least by contiguous values during the program load, it might help your compiler to generate a better jump table for your switch, which might help increasing the speed of the programs.

The assumption here is that your care more about the speed during the execution and that a little slowdown during the program load isn't a problem if it can otherwise improve performance.
I guess that you want your programs to be fast while they run and that a small slowdown when it terminates isn't one of your concerns if you can otherwise speed your program up. Therefore, if your compiler supports it (I guess it does), you could use __builtin_expect to influence branch prediction while the program runs:

switch (*ip) {
    case '&lt;':
        if (__builtin_expect(--ptr &lt; mem, false)) {
            return i + 1;
        }
        break;
    case '&gt;':
        if (__builtin_expect(++ptr &gt;= mem + sizeof mem, false)) {
            return i + 1;
        }
        break;
    // ...
}


It would however be a bad idea to influence branch prediction for the conditions in the cases of [ and ]. The results are too prone to change to risk a pessimization.


I would have some other small remarks but I will keep them for myself since they would be considered a matter of style and you know what you're doing anyway :)