Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
288 views
in Technique[技术] by (71.8m points)

c++11 - Can you make a computed goto in C++

Fortran has a computationally efficient called a 'computed goto'. The construct uses an index into a branch table to perform a direct goto. If I remember correctly the syntax is:

go to index (label1, label2, ...)

where the index is used to reference a code pointer (label) in the parenthesized list.

I have a case where a computed goto is a better solution than a switch statement and would like to construct one but can't figure out how.

Now before the jibes and slings arrive, it is possible for the compiler to optimize a computed goto, but I have no guarantee that it will.


A switch statement can always be used. In some cases a switch statement can be optimized to a jump table (the implementation of a computed goto). However, this is only possible when the range of case values is an almost dense covering (there is almost a case statement for each integer in the range of low values to high values). When this is not the case, the implementation will probably be a binary tree. The compiler writer has a choice to optimize to a jump table when appropriate or not. Where a binary tree will always satisfy the semantics of a switch statement, where sometimes a jump table is sufficient lets me ask whether I can guarantee a jump table when appropriate. I have no control over the compiler writer.

As a simple case, I often write lexers (FSM's), and I use three data constructs, one to map the input into an acceptable alphabet, one to perform node transitions, and one to execute some code based on the current state and the input value. The implementation of the FSM is a Mealy Machine, not a Moore Machine, so actions are performed on arcs (transitions) and not on nodes.

The actions performed are typically small, often no more than a line of source code. I recognize that functions can be used, and that their use removes the need for a jump table. But I believe that I can not 'point' to an inline function, therefore, functions are closed form callable procedures. This is less efficient in most cases, than a switch statement w/wo jump table optimization. If I can use a jump table then I avoid the issue of what the compiler writer thinks of optimization and am able to write efficient code.

As to the general case brought up below about the issues related to a Fortran computed goto. This is not a criticism of that/those comment. But the qualitative issues, even though they are true, does not answer the question.

There is an answer below void* &&label; and I'd like to thank you for that. But, alas, as you pointed out this is non-standard C/C++ and is likely not to be present in the future. So, it's better not to do this.

I hope that I've answered the 'get a better compiler' comment. And I hope I've at least addressed the issues with using function pointers. And at last, this was a moment of curiosity for me. I didn't think that I should provide the germicidal history of why I thought the question had some carrying power. But now I know. Whenever, and I mean whenever, I write to this group I better tell you what all my duckies are so that they can be shot down good and proper.

Thanx everyone.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you compile with a recent GCC compiler (e.g. GCC 7 or GCC 6) -or even, for C code, older versions of GCC- you could use its labels as values language extension (so outside of C++11 or C++14 standards), which works with both C & C++. The prefix && operator gives the address of a label, and the goto is computed if followed by * indirection operator. You'll better have target labels starting some blocks.

For example:

#include <map>

int foo (std::map<int,int>& m, int d, int x) {
    static const void* array[] = {&&lab1, &&lab2, &&lab3 };
    goto *array[d%3];
lab1: {
        m[d]= 1;
        return 0;
    };
lab2: {
        m[2*d]=x;
        return 1;
    }
lab3: {
    m[d+1]= 4*x;
    return 2;
    }
}    

(of course, for the above code, a plain switch would be preferable, and probably as efficient)

BTW, recent Clang (e.g. clang++-5.0) also accepts that extension.

(computed gotos are not exception-friendly, so they could disappear in future versions of GCC for C++)

And with threaded code programming techniques, you could write some quite efficient (bytecode) interpreters using that, and in that particular case the code stays very readable (because it is very linear) and is quite efficient. BTW, you could hide such computed gotos with macros and conditional compilation -e.g. #if-s- (e.g. to use instead switch on compilers not supporting that extension); then your code would be quite portable. For an example in C, look into Ocaml's runtime/interp.c


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...