Lightweight C Exception Library // names are unique within a function, any valid variable name
// a jump table try, allowing return values to determine the exception thrown(index in a jump table, -1 being success for example)
// you only need to put in what you need, not all exceptions, or total exception count
#define GTRY(name, exc) void* __jt_##name[exc];int __jtix_##name = 0;
// register an exception in the jump table. you don't need to do them all
#define GTEX(name, exception) __jtix_##name;__jt_##name[__jtix_##name++] = &amp;&amp;__tr_##exception##name;
// resets the jump table index to a given value, useful for overwriting exceptions without a new try.
#define GTRST(name, index) __jtix_##name = index;
// a standard try, doesn't actually add anything, but for cleanliness.
#define TRY(name) ;
// throw an exception by name
#define THROW(name, exception) goto __tr_##exception##name;
// throws an exception by jump table index
#define GTHROW(name, exn) goto *__jt_##name[exn];
// begins a catch block
#define CATCH(name, exception) goto __trend_##name;__tr_##exception##name:;
// signifies where the try ends
#define ENDTRY(name) __trend_##name:;
// 'finally' blocks need only be put after an end try.


Usage Example: 

int main(int argc, char* argv[]) {
    TRY(magic)
    THROW(magic, EOF)
    CATCH(magic, EOF)
    printf("eof!\n");
    ENDTRY(magic)
    printf("complete\n");
    GTRY(fagic, 2)
    int eof = GTEX(fagic, EOF)
    int rst = GTEX(fagic, RST)
    GTHROW(fagic, rst)
    CATCH(fagic, EOF)
    printf("eof2!\n");
    CATCH(fagic, RST)
    printf("rst\n");
    ENDTRY(fagic);
    //
    TRY(nest) {
        THROW(nest, EOF);
    } CATCH(nest, EOF) {
        printf("eof3!\n");
    }
    ENDTRY(nest)
    printf("complete3\n");
    return 0;
}


My purpose was to create a macro-based exception system that can run on embedded devices with ease(magic is done compile-time). There is a potential performance malice if CPUs don't support labels as values and GTRY is used.
Semantics
In the languages that implement try, throw and catch the scope is generally larger than a single function. The scope of the exception handling is set by the try block and the catch block. The C goto is limited to the current function, to jump outside of the current function you need to use setjmp() and longjmp(). Your implementation does not seem to use setjmp() and longjmp().

Maintainability
Using a goto is generally decreasing maintainability, hiding a goto is a bad idea. If I have to maintain code that contains a goto I want to be able to immediately know that there is a goto and I want to be able to find the label immediately as well.

Performance
A reason to use goto is to improve performance. When goto's actually degrade performance that is another reason not to use them.