ViKo 1 3 июня, 2012 Опубликовано 3 июня, 2012 · Жалоба Можно сделать массив указателей на низкоуровневые функции. А в функции верхнего уровня по индексу вызывать один уз указателей. Но отъедаются ресурсы на вызов низкоуровневой функции и возврат из нее. Как бы сделать это в виде массива из меток на низкоуровневые части, которыми набита одна функция верхнего уровня? Можно, конечно, в виде switch - case... Наверное, зря я голову ломаю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 46 3 июня, 2012 Опубликовано 3 июня, 2012 · Жалоба Можно сделать массив указателей на низкоуровневые функции. А в функции верхнего уровня по индексу вызывать один уз указателей. Но отъедаются ресурсы на вызов низкоуровневой функции и возврат из нее. Как бы сделать это в виде массива из меток на низкоуровневые части, которыми набита одна функция верхнего уровня? А как с параметрами тех функций? Они у всех ваших функций одинаковы? Или при каждом вызове вы будете переопределять указатель? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maksimp 0 3 июня, 2012 Опубликовано 3 июня, 2012 · Жалоба Как бы сделать это в виде массива из меток На стандартном Си нельзя. Но GCC имеет такую возможнось: http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html 6.3 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 statement1, 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; Note that this does not check whether the subscript is in bounds—array indexing in C never does that. 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. 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); 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. The &&foo expressions for the same label might have different values if the containing function is inlined or cloned. If a program relies on them being always the same, __attribute__((__noinline__,__noclone__)) should be used to prevent inlining and cloning. If &&foo is used in a static variable initializer, inlining and cloning is forbidden. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 3 июня, 2012 Опубликовано 3 июня, 2012 · Жалоба А как с параметрами тех функций? Они у всех ваших функций одинаковы? Или при каждом вызове вы будете переопределять указатель? А у них нет параметра. void. Приходит, к примеру, по последовательному порту команда (индекс в том самом массиве), нужно ее выполнить. На стандартном Си нельзя. Но GCC имеет такую возможнось: Это пробежал по диагонали. Во-первых, у меня не GCC... :laughing: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 4 июня, 2012 Опубликовано 4 июня, 2012 (изменено) · Жалоба 1. Определитесь с терминологией: массив указателей на метки или массив указателей на функции ?! 2. В случае массива с указателями на функции: // количество обработчиков #define N_FUNC 16 // тип функции-обработчика typedef void(TypFunc)(void); // прототипы обработчиков для массива TypFunc f1; TypFunc f2; ... TypFunc f16; // сам массив указателей TypFunc * mas_func[N_FUNC] = {f1,f2,.....,f16}; unsigned int nfunc; // индекс функции-обработчика void main (void) { ... // необходимым вам образом вычисляете nfunc ... if(nfunc < N_FUNC) mas_func[nfunc](); // вызов необходимого обработчика ... } TypFunc f1 {...} ... TypFunc f16 {...} Код ДОЛЖЕН работать на любом Си, в том числе и стандартном, т.к. здесь нет никагого противоречия со стандартом. Проверял на нескольких разных компиляторах/платформах 3. Реализацию с метками описал maksimp. Хотя с На стандартном Си нельзя. я все же не совсем согласен 4. На чем и как написаны эти низкоуровневые обработчики? На асме или на Си? Если на Си или асме в виде отдельных функций, то "goto" использовать нельзя, т.к. будет использоваться пролог одной функции, а эпилог другой, и они скорее всего будут не симетричные. Если обработчики - это куски кода, то проще использовать "switch-case". Некоторые компиляторы сами оптимизируют такой программый код под вызод функций (при этом создается секция .switch, хранящая переходы оператора). Изменено 4 июня, 2012 пользователем alexeyv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба Как бы сделать это в виде массива из меток на низкоуровневые части, которыми набита одна функция верхнего уровня? Это называется Forth-ядро, т.н. шитый код. Проблема только в том, что при реализации на си быстродействия не добавит. А при реализации на уровне ассемблера будут проблемы стыковки с сишной инфраструктурой. А и действительно, чем switch не устраивает? Если сильно критично быстродействие, можно мелкие функции заинлайнить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба 1. Определитесь с терминологией: массив указателей на метки или массив указателей на функции ?! Именно так вопрос и ставил: "Массив указателей на метки" или "Массив указателей на функции". Массив указателей на функции, кстати, можно сделать не глобальным, а внутри функции верхнего уровня. Проблема только в том, что при реализации на си быстродействия не добавит. А и действительно, чем switch не устраивает? Устроил бы и switch. Но выбор сделал в пользу массива указателей на функции. Классическое решение. Вопрос приобрел чисто теоретический смысл. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба Вопрос приобрел чисто теоретический смысл. :) Использую массив указателей на функции в программах для шести семейств контроллеров, для некоторых семейств вызов функции по индексу массива вызывает ужОс. Не мешало бы глянуть в дизассемблере. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба Использую массив указателей на функции в программах для шести семейств контроллеров, для некоторых семейств вызов функции по индексу массива вызывает ужОс. Не мешало бы глянуть в дизассемблере. У меня STM32. Там усе супэр! Вопрос уже и теоретический смысл потерял. Так как case - это и есть метки. Возможно, даже собранные компилятором в массив. Позже попробую, посмотрю дизасемблерный листинг. Для обоих вариантов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 29 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба У меня STM32. Там усе супэр! case - это и есть метки. Возможно, даже собранные компилятором в массив. Если индексы по порядку и их много - должен упаковать в таблицу. У ИАРа для MSP430 (других не пробовал) есть такая фича для оптимизации switch - even_in_range (индексы подряд, четные и в ограниченном диапазоне). Получается таблица адресов и переход в одну инструкцию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба Если индексы по порядку и их много - должен упаковать в таблицу. У ИАРа для MSP430 (других не пробовал) есть такая фича для оптимизации switch - even_in_range (индексы подряд, четные и в ограниченном диапазоне). Получается таблица адресов и переход в одну инструкцию. Да, индексы будут подряд идти. Сам выбираю набор команд. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kolobok0 0 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба ... Так как case - это и есть метки... Вы сами ответили на свой вопрос. В общем случае - сишная конструкция switch->case есть массив и переход по нему. иногда заменяется на пару ифов, если кэйсов не очень много. но с точки зрения оптимизации - свитч-кэйс более оптимально по скорости, т.к. прямой переход а не куча сравнений. подготовка индекса как правило занимает не очень много времени. при большом кол-ве меток, как правило включается двух уровневая оптимизация. но стоит сказать, что это функционал самого перехода; а не переход+разные обработчики (на уровне функций) - что на азме можно реализовать на прямую(т.е. хранить кэйсы не как адреса разветвления, а как адреса самих функций обработчиков). языки верхних уровней в этом плане из за простоты реализации - проигрывают по скорости. хотя заставить оптимизатор свернуть лишнии колы, наверное возможно... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 4 июня, 2012 Опубликовано 4 июня, 2012 · Жалоба У ИАРа для MSP430 (других не пробовал) есть такая фича ИАР AVR при большом количестве case формирует массив указателей сам. Другие наверняка тоже. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться