Для получения адреса метки, заданной в текущей позиции(или вернее содержащейся
внутри функции), применяется унарный оператор `&&', а значение передаваемое по этому
адресу имеет тип void *. Оно является константой и может быть использовано везде,
в пределах области определения функции. Для примера:
Самым распространенным способом использования константных значений является
инициализацией статического массива, который будет работать как
таблица переходов(jump table):
После чего можно, выбирать метку, используя индиксацию массива.
Помните, что в языке программирования Си, никогда не проверяются границы
индиксируемого массива.
Другое использование таблицы переходов со значениями меток является интерпретация
кода потоков(threaded code). Для повышения быстроты диспетчеризации, в пределах
интерпретируемой функции-потока, метки могут быть сохранены в её коде.
Когда Вы использует этот метод для перехода по коду в различных функциях помните,
что способ избежать всяких несуразностей – сохранение адреса значения метки
только в автоматически создаваемых переменных и ни в коим случае не передавать
значение этих меток в качестве аргумента, вызваемой функции.
/* The file jump_table_test.c
*
* build: gcc jump_table_test.c -o jump_table_test */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Проверка на предопределения макроса __GNUC__ */
#ifndef __GNUC__
#error "It's nonsense!The macros __GNUC__ is not predefined."
#else
#warning "The macros __GNUC__ is always predefined by the GNU CC preprocessor!"
#endif
#define NKEYS 5
#define KEY_ONE "key1"
#define KEY_TWO "key2"
#define KEY_THREE "key3"
#define KEY_FOUR "key4"
#define KEY_NOTFOUND "Key not found"
typedef struct jump_table_struct {
const char *name; /* имя длинной опции командной строки */
const void *jump; /* Указатель на константу -- метки перехода */
} jump_table_struct_t;
/* Функция bsearch() будет вызывать по указателю compare
* функцию compare_jump_table_structs() для сравнения каждого элемента массива,
* передаваемого по указателю ch_p с ключом-значением по указателю array_p */
static int compare_jump_table_structs(const void *ch_p, const void *array_p)
{
return strcmp(((const jump_table_struct_t*)ch_p)->name,
((const jump_table_struct_t*)array_p)->name);
}
static const char *gnucc_ext_labels_as_values_test( const char buf[] )
{
jump_table_struct_t *found; /* текущая метка перехода*/
/* Таблица перехода */
static const jump_table_struct_t jump_table[] = {
{ KEY_ONE, &&case_Key1 }, /* Ключ 1 */
{ KEY_TWO, &&case_Key2 }, /* Ключ 2 */
{ KEY_THREE, &&case_Key3 }, /* Ключ 3 */
{ KEY_FOUR, &&case_Key4 }, /* Ключ 4 */ };
/* Рассчет количества меток перехода */
const int jump_table_count = sizeof(jump_table)/sizeof(jump_table_struct_t);
jump_table_struct_t findme = { buf, NULL };
/* Поиск метки перехода */
found = bsearch(&findme, jump_table, jump_table_count,
sizeof(jump_table_struct_t), compare_jump_table_structs );
if(!found) return KEY_NOTFOUND;
/* Переход по адресу значения метки, если она была найдена
* по ключу, переданного в переменной buf[] данной функции */
goto *(found->jump);
case_Key1:
return found->name; /* Ключ, переданный по указателю key_p,
соответсвует "Key1" */
case_Key2:
return found->name; /* Ключ, переданный по указателю key_p,
соответсвует "Key2" */
case_Key3:
return found->name;/* Ключ, переданный по указателю key_p,
соответсвует "Key3" */
case_Key4:
return found->name;/* Ключ, переданный по указателю key_p,
соответсвует "Key4" */
}
int
main( int argc, char **argv )
{.
char *result = NULL;
const char *key_p = *(argv+1);
fprintf(stdout,"The programm jump_table_test, version 0.1\n" );
fprintf(stdout,"This test was written by Andrey Rjavskov(Rzhavskov)\n" );
if( argc != 2 ) {
fprintf (stderr,"Usage: jump_table_test \nfailure.\n");
fflush(stderr);
return EXIT_FAILURE;
}
result=(char*)gnucc_ext_labels_as_values_test(key_p);
return fprintf(stdout, "You have entered next key: %s\n%s.\n",
result,
!strcmp(result,KEY_NOTFOUND) ? "failure" : "done" );
}
/*eof*/