Is it possible to store the address of a label in

2019-01-21 05:49发布

I know everyone hates gotos. In my code, for reasons I have considered and am comfortable with, they provide an effective solution (ie I'm not looking for "don't do that" as an answer, I understand your reservations, and understand why I am using them anyway).

So far they have been fantastic, but I want to expand the functionality in such a way that requires me to essentially be able to store pointers to the labels, then go to them later.

If this code worked, it would represent the type of functionality that I need. But it doesn't work, and 30 min of googling hasn't revealed anything. Does anyone have any ideas?

int main (void)
{
  int i=1;
  void* the_label_pointer;

  the_label:

  the_label_pointer = &the_label;

  if( i-- )
    goto *the_label_pointer;

  return 0;
}

14条回答
何必那么认真
2楼-- · 2019-01-21 05:53

You can assign label to variable using &&. Here is your modified code.


int main (void)
{
  int i=1;
  void* the_label_pointer = &&the_label;

  the_label:


  if( i-- )
    goto *the_label_pointer;


  return 0;
}
查看更多
等我变得足够好
3楼-- · 2019-01-21 06:00
#include <stdio.h>

int main(void) {

  void *fns[3] = {&&one, &&two, &&three};   
  char p;

  p = -1;

  goto start; end:   return 0;     
  start:   p++;   
  goto *fns[p];
  one:  printf("hello ");  
  goto start;  
  two:  printf("World. \n");  
  goto start;
  three:  goto end;
}
查看更多
手持菜刀,她持情操
4楼-- · 2019-01-21 06:01

I know the feeling then everybody says it shouldn't be done; it just has to be done. Here's how to do it:

#define jumpto(a) asm("jmp *%0"::"r"(a):)

int main (void)
{
  int i=1;
  void* the_label_pointer;

  the_label:

  the_label_pointer = &&the_label;

  if( i-- )
    jumpto(the_label_pointer);

  return 0;
}

The label dereferencing operator && will only work with gcc. And obviously the jumpto assembly macro needs to be implemented specifically for each processor (this one works with both 32 and 64 bit x86). Also keep in mind that there is no guarantee that the state of the stack is the same at two different points in the same function. And at least with some optimization turned on it's possible that the compiler assumes some registers to contain some value at the point after the label. These kind of things can easily get screwed up then doing crazy shit the compiler doesn't expect. Be sure to proof read the compiled code.

查看更多
相关推荐>>
5楼-- · 2019-01-21 06:04

The switch ... case statement is essentially a computed goto. A good example of how it works is the bizarre hack known as Duff's Device:

send(to, from, count)
register short *to, *from;
register count;
{
    register n=(count+7)/8;
    switch(count%8){
    case 0: do{ *to = *from++;
    case 7:     *to = *from++;
    case 6:     *to = *from++;
    case 5:     *to = *from++;
    case 4:     *to = *from++;
    case 3:     *to = *from++;
    case 2:     *to = *from++;
    case 1:     *to = *from++;
        }while(--n>0);
    }
}

You can't do a goto from an arbitrary location using this technique, but you can wrap your entire function in a switch statement based on a variable, then set that variable indicating where you want to go, and goto that switch statement.

int main () {
  int label = 0;
  dispatch: switch (label) {
  case 0:
    label = some_computation();
    goto dispatch;
  case 1:
    label = another_computation();
    goto dispatch;
  case 2:
    return 0;
  }
}

Of course, if you do this a lot, you'd want to write some macros to wrap it.

This technique, along with some convenience macros, can even be used to implement coroutines in C.

查看更多
爷的心禁止访问
6楼-- · 2019-01-21 06:05

Use function pointers and a while loop. Don't make a piece of code someone else will have to regret fixing for you.

I presume you're trying to change the address of the label somehow externally. Function pointers will work.

查看更多
贪生不怕死
7楼-- · 2019-01-21 06:06

You can do something similar with setjmp/longjmp.

int main (void)
{
    jmp_buf buf;
    int i=1;

    // this acts sort of like a dynamic label
    setjmp(buf);

    if( i-- )
        // and this effectively does a goto to the dynamic label
        longjmp(buf, 1);

    return 0;
}
查看更多
登录 后发表回答