解释器中对 标号 的使用

android_6200/dalvik/vm/mterp/out/InterpC-portdbg.c  + 467

c89也支持

向我这样看待码永远都学不好程序,感觉好迷茫,谁么时候能有个整体的认识?!

写个示意程序:

      1 #include <stdio.h>                                                                                                                                                           
      2 #include <stdlib.h>
      3
      4 #define H(_op)  &&op_##_op
      5 #define HANDLE_OPCODE(_op) op_##_op:
      6
      7 #define DEFINE_GOTO_TABLE(_name) \
      8     static const void * _name[8] = {    \
      9         H(OP_NOP),                      \
     10         H(OP_MOVE),                     \
     11         H(OP_MOVE_16),                  \
     12         H(OP_MOVE_WIDE),                \
     13         H(OP_MOVE_OBJECT),              \
     14         H(OP_RETURN_WIDE),              \
     15         H(OP_CONST_4),                  \
     16         H(OP_CONST)                     \
     17     }
     18
     19 int main(void)
     20 {
     21     DEFINE_GOTO_TABLE(handlerTable);
     22
     23     goto *handlerTable[7];
     24
     25
     26 HANDLE_OPCODE(OP_NOP)
     27     printf("OP_NOP\n");
     28     exit(1);
     29 HANDLE_OPCODE(OP_MOVE)
     30     printf("OP_MOVE\n");
     31     exit(1);
     32 HANDLE_OPCODE(OP_MOVE_16)
     33     printf("OP_MOVE_16\n");
     34     exit(1);
     35 HANDLE_OPCODE(OP_MOVE_WIDE)
     36     printf("OP_MOVE_WIDE\n");
     37     exit(1);
     38 HANDLE_OPCODE(OP_MOVE_OBJECT)
     39     printf("OP_MOVE_OBJECT\n");
     40     exit(1);
     41 HANDLE_OPCODE(OP_RETURN_WIDE)
     42     printf("OP_RETURN_WIDE\n");
     43     exit(1);
     44 HANDLE_OPCODE(OP_CONST_4)
     45     printf("OP_CONST_4\n");
     46     exit(1);
     47 HANDLE_OPCODE(OP_CONST)
     48     printf("OP_CONST\n");
     49     exit(1);
     50
     51
     52     return 0;
     53 }

参见:http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Labels-as-Values.html#fn-1

Labels as Values

&&又冒出个神奇的作用

You can get the address of a label defined in the current function (or a containing function) with the unary operator &&.

The value has type void *. This value is a constant and can be used wherever a constant of that type is valid. For example:

     void *ptr;
     ...
     ptr = &&foo;
     

To use these values, you need to be able to jump to one. This is done with the computed goto statement, goto *exp;. For example,

     goto *ptr;
     

Any expression of type void * is allowed.

One way of using these constants is in initializing a static array that will serve as a jump table:用法

     static void *array[] = { &&foo, &&bar, &&hack };
     

Then you can select a label with indexing, like this:

     goto *array[i];
     

Note that this does not check whether the subscript is in bounds--array indexing in C never does that.

相比较于switch语句:

Such an array of label values serves a purpose much like that of the switch statement. The switch statement is cleaner, so use that rather than an array unless the problem does not fit a switch statement very well.

dalvik虚拟机中如上,使用了该方法。

Another use of label values is in an interpreter for threaded code. The labels within the interpreter function can be stored in the threaded code for super-fast dispatching.

不可跨函数You may not use this mechanism to jump to code in a different function. If you do that, totally unpredictable things will happen. The best way to avoid this is to store the label address only in automatic variables and never pass it as an argument.

An alternate way to write the above example is

     static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                                  &&hack - &&foo };
     goto *(&&foo + array[i]);
     

在动态库中的用法:

This is more friendly to code living in shared libraries, as it reduces the number of dynamic relocations that are needed, and by consequence, allows the data to be read-only.

 

看看宏定义中的局部标号:

Locally Declared Labels

Each statement expression is a scope in which local labels can be declared. A local label is simply an identifier; you can jump to it with an ordinary goto statement, but only from within the statement expression it belongs to.

A local label declaration looks like this:

     __label__ label;
     

or

     __label__ label1, label2, ...;
     

Local label declarations must come at the beginning of the statement expression, right after the ({, before any ordinary declarations.

The label declaration defines the label name, but does not define the label itself. You must do this in the usual way, with label:, within the statements of the statement expression.

The local label feature is useful because statement expressions are often used in macros. If the macro contains nested loops, a goto can be useful for breaking out of them. However, an ordinary label whose scope is the whole function cannot be used: if the macro can be expanded several times in one function, the label will be multiply defined in that function. A local label avoids this problem. For example:

     #define SEARCH(array, target)                     \
     ({                                                \
       __label__ found;                                \
       typeof (target) _SEARCH_target = (target);      \
       typeof (*(array)) *_SEARCH_array = (array);     \
       int i, j;                                       \
       int value;                                      \
       for (i = 0; i < max; i++)                       \
         for (j = 0; j < max; j++)                     \
           if (_SEARCH_array[i][j] == _SEARCH_target)  \
             { value = i; goto found; }                \
       value = -1;                                     \
      found:                                           \
       value;                                          \
     })

 

 

posted on 2012-12-14 18:07  阿加  阅读(1060)  评论(0编辑  收藏  举报

导航