[LCP]Address of a label
David Spencer
David.W.Spencer at oracle.com
Fri Feb 22 22:50:25 UTC 2002
> 1. This one is allowed only in GCC (it's a GNU extension):
>
> void * ptr;
> ...
> ptr = &&label;
> ...
> goto *ptr;
Hmm. Well, it's your code, so you can do whatever you like, but gotos
are evil, and you should only be using them if you absolutely need to,
which in virtually all cases you don't. There are better ways of
handling this situation than using a goto.
>
> 2. This one is quite good idea, and portable too.
>
> #define label(x) do_something ## x
>
> goto label(1);
>
> do_something1:
> ...
> do_something2:
> ...
compare:
goto label(n) switch (n)
do_something1: case 1:
goto/return break;
do_something2: case 2:
goto/return break;
I don't see what benefit does this have over the original switch.
It takes up just as much screen real estate, and fundamentally there's
nothing wrong with a huge switch statement, whereas there is
fundamentally something wrong with a goto, and you're going to have to
have a goto at the end of each section, or a return, so you may as well
use break. (In fact large switches used to be the norm within Windows
programs where you switched events, and often switched within individual
events as well, WM_COMMAND is a good example. The outer switch would
process WM_COMMAND, WM_MOUSEMOVE, WM_TIMER etc, and the WM_COMMAND case
would contain a switch for the various gadgets in a dialog box (and
individual gadgets may require switches as well, a button for instance
may do different things in different circumstances).)
The only disadvantage to a switch that I can think of is that I *think*
it is implemented as an if/else if ladder, so for a switch statement
with 200 equally probably cases you will have on average 100 comparisons
per bytecode, which could be a little inefficient. An optimising
compiler might spot the fact that it is sequential and implement a
computed goto and/or jumptable but you'd have to examine the assembler
output to be sure.
A computed goto equivalent could be done with an array of structs:
struct bytecodes
{
void (*func)();
} multiplexer[200];
(You can do an array of function pointers (void (*func[200])() I think)
as well but I've struct-ed it as you may have other info pertinent to
each function. You don't need to store the bytecode in the structure as
the array index corresponds to the bytecode.)
function prototypes:
void summat1();
void summat2();
void summat3();
then in a setup function:
multiplexer[0].func = summat1;
multiplexer[1].func = summat2;
multiplexer[2].func = summat3;
or multiplexer[SOME_BYTE_CODE].func... might be more readable where
SOME_BYTE_CODE is part of an enum or something.
then in the decode
if (validate(bytecode))
{
// this single line is where your switch/goto
// spaghetti would have been
(*(multiplexer[bytecode].func))();
}
This would be more efficient as the address of func would be calculated
using ordinary array accessing code, then a simple dereference gets the
address of the function.
Updating this code would be simple as the actual call would remain
constant and you would only need to modify prototypes and the array
initialiser. Large switches are not easy to navigate.
This doesn't handle parameters of course but these could be added in a
generic way; we don't know what these params are pointing to but the
context - namely the fact that this is "summat1" - determines that.
e.g. because it is summat1, param1 is a float and param2 is ignored,
that sort of stuff.
void summat1(void *param1, void *param2);
and
void summat1(void *param1, void *param2)
{
float theFloat = *((float*)param1); // (float) *param1 ???
}
then call it with
(*(bytecodes[bytecode].func))((void*)¶m1, (void*)¶m2);
I haven't tested this, and I'd have to compile it to make sure the
syntax is correct, but it shouldn't be far off. I might use this idea
for my z80 emulator...
--
David Spencer
www.curlypi.com
More information about the linuxCprogramming
mailing list