Can You Make a Computed Goto in C++

Can you make a computed goto in C++?

using jump_func_t = void(*)(void const*);
template<class F>
jump_func_t jump_func() {
return [](void const*ptr){ (*static_cast<F const*>(ptr))(); };
}
template<class...Fs>
void jump_table( std::size_t i, Fs const&...fs ) {
struct entry {
jump_func_t f;
void const* data;
void operator()()const { f(data); }
};
const entry table[] = {
{jump_func<Fs>(), std::addressof(fs)}...
};
table[i]();
}

Test code:

int x = 0, y = 0, z = 0;
jump_table( 3,
[&]{ ++x; },
[&]{ ++y; },
[&]{ ++z; },
[&]{ ++x; ++z; }
);
std::cout << x << y << z << "\n";

outputs 101.

Live example

If you want large amounts of gaps, extra work will have to be done. Short "gaps" can be handled with invalid jump target:

using action = void();
static action*const invalid_jump = 0;

which should segmentation fault if actually called.

For a really sparse table, you'd want to pass in compile-time constants for table size and compile time indexes of each target, then build the table up from that. Depending on how efficient you want to be, that may require reasonably fancy compile time programming.

GCC computed goto and value of stack pointer

In general, when you have a function with labels whose address is taken, gcc needs to ensure that you can jump to that label from any indirect goto in the function -- so it needs to layout the stack so that the exact stack pointer doesn't matter (everything is indexed off the frame pointer), or that the stack pointer is consistent across all of them. Generally, this means it allocates a fixed amount of stack space when the function starts and never touches the stack pointer afterwards. So if you have inner scopes with variables, the space will be allocated at function start and freed at function end, not in the inner scope. Only the constructor and destructor (if any) need to be tied to the inner scope.

The only constraint on jumping to labels is the one you noted -- you can only do it from within the function that contains the labels. Not from any other stack frame of any other function or interrupt handler or anything.

edit

If you want to be able to jump from one stack frame to another, you need to use setjmp/longjmp or something similar to unwind the stack. You could combine that with an indirect goto -- something like:

if (target = (void *)setjmp(jmpbuf)) goto *target;

that way you could call longjmp(jmpbuf, label_address); from any called function to unwind the stack and then jump to the label. As long as setjmp/longjmp works from an interrupt handler, this will also work from an interrupt handler. Also depends on sizeof(int) == sizeof(void *), which is not always the case.

How to goto into different function in c?

But what about the children? stack?

goto between functions doesn't make any sense if you think about the stack. What will be on the stack when you jump? The source and destination functions could potentially have different arguments and a different return value. Who will the new function return to? Will its return value even make sense to the caller? The caller called the source function, not the destination function.

Return to caller?

Consider your example closely:

int main()
{
test();
main_next:
printf("hello, world");
}

void test()
{
goto main_next;
}

What happens when the goto executes? I presume you'd want this to jump up the stack back to the calling main() function. The goto would effectively be the same as a return, changing the call stack from:

main()                            main()
| to
+--> test()

But what if you wanted to jump to a function that isn't in the call stack? What then?

Or replace the current function?

A different interpretation is that the goto would replace the existing test() call with one to main(). The call stack would change from:

main()                            main()
| to |
+--> test() +--> main()

Now main() is recursively calling itself, and the lower main() will return to the upper main()—who, by the way, is expecting a void return value but is going to receive an int.

setjmp and longjmp

The closest you can get is with setjmp / longjmp. These allow you to save and restore the stack context for nonlocal goto, allowing you to jump between function calls.

setjmp and longjmp get around the problems I described by (a) saving and restoring the full stack context when jumping, and (b) not allowing jumps if the stack context is no longer valid. I quote from the man page (emphasis mine):

setjmp() and longjmp(3) are useful for dealing with errors and interrupts encountered in a low-level subroutine of a program. setjmp() saves the stack context/environment in env for later use by longjmp(3). The stack context will be invalidated if the function which called setjmp() returns.

To put it another way, longjmp is basically the C equivalent of throwing an exception. A low-level function can unwind the call stack and resume execution at a much higher level function.

It's also awfully tricky to use, and rarely a good idea. Again, from the man page:

setjmp() and sigsetjmp() make programs hard to understand and maintain. If possible an alternative should be used.

What is an indirect goto statement?

There is a GNU extension that allows taking an address of a label, storing it for later use, then goto that address at a later point. See https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html for details. Example:

    void *ptr;

if(...)
ptr = &&foo;
else
ptr = &&bar;

/* ... */
goto *ptr;

foo:
/* ... */

bar:
/* ... */

Clang supports that too, as it aims at being compatible with GCC.

The use of the above might be, for example, in implementing state machines.



Related Topics



Leave a reply



Submit