Home > front end >  Building exceptions in C using setjmp and longjmp
Building exceptions in C using setjmp and longjmp

Time:11-21

I am trying to implement exceptions in C using longjmp and setjmp. I can get the simple case to work. However I would like nested exceptions to work. As a design decision the exceptions cant't use malloc and must use the stack. To implement the linked list for nested exceptions it seems like I have use global variable declarations. I would like to avoid this. Is there a way to fetch a global address in C without declaring a global variable? I would like to use list functions without them operating on global variables but I want a global address because if I use a local address it goes away when the function exits. The variables lose scope.

I am using this website as inspiration and guidance. http://www.on-time.com/ddj0011.htm Here is the simple case:

struct XRecord {
   size_t id;
   jmp_buf context;
};

struct XRecord __global_exception_record;    

float divide(float a, float b) {
    
    if (b == 0.0f) {
        //XRAISE(DIVIDE_BY_ZERO)
        
        longjmp(__global_exception_record.context, DIVIDE_BY_ZERO);
    }
    float c = a / b;
    return c;
}


switch (setjmp(__global_exception_record.context)) {
    case XCODE:
    {
        printf("start code block\n");
        float c = divide(4.0f, 2.0f);
        float d = divide(4.0f, 0.0f);
        break;
    }
    case DIVIDE_BY_ZERO:
        printf("error: division by zero\n");
        break;

    default:
        printf("some other error occcured\n");
        break;
}

Nested exceptions will not work because it needs an additional jumper buf to handle the two exception blocks. If I store the jumper buf in a record and put it in a link list it has to be global or the variables lose scope. I need a way to fetch a global address. Can this be done using assembly. I am not familiar with assembly at all.

CodePudding user response:

Is there a way to fetch a global address in C without declaring a global variable? I would like to use list functions without them operating on global variables but I want a global address because if I use a local address it goes away when the function exits. The variables lose scope.

Let's be precise: C does not have global variables per se. What people typically mean when they say that is variables with

  • static storage duration and
  • external linkage.

C doesn't say anything at all about a call stack, but in a typical implementation, that's how block-scope variables are allocated. These have

  • automatic storage duration and
  • no linkage.

Among the other possibilities are dynamically allocated objects, which have

  • allocated storage duration and
  • anonymity

You seem to be asking for a combination of static storage duration and anonymity, but this is not available. Nor does C have a concept of an abstract address. In C there are addresses of objects and addresses of functions.

You can achieve your anonymity objective, sort of, with allocated storage. However, although that provides anonymity of the object itself, at some level you still need a named object containing a pointer that leads you to or at least towards the allocated object. Possibly you could arrange to pass that to all your functions through function arguments, so that there is no external name involved, but that would be very intrusive.

If you accept that you need at least one external name, somewhere, but you want to prevent direct access to the object in question, then you can use a static local variable of an external function, or a static file-scope variable accessed via one or more external functions in the same translation unit. For example,

void *get_storage(void) {
    char *the_storage[STORAGE_SIZE];  // static storage duration; no linkage
    return the_storage;
}

But it's hard to see what that gains you over direct access to the_storage.

A similar alternative would be to make the storage a static, file-scope object (static storage duration and internal linkage) and make all access go through utility functions that do the wanted job (e.g. push nested exception / pop nested exception) without making the storage itself directly accessible.

  • Related