Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Компоновка и компиляция функций, определенных внутри другой

Чт ноя 21, 2019 11:22:03

Вопрос может не столько по ARM, сколько по Сям, но родился он у меня на STM32 и с IDE CooCox и компилятором GCC. Собственно проблема вот в чем, я решил так сказать для ограничения видимости и для использования внутри функций сделать определение функций, указатели на которые я собрал в массив, определить внутри другой функции. То есть прописал что-то типа такого:
Код:
s16 read_value()
{
   static s16 temp;
   TYPE_BYTES_WORD Type_F,Data1,Data2;
   u16 temp2;
   void some_fnc1()
   {
      //здесь на самом деле идет какая-то обработка
   }
   void some_fnc2()
   {
      //здесь на самом деле идет какая-то обработка
   }
   void some_fnc3()
   {
      //здесь на самом деле идет какая-то обработка
   }
   void (*fnc_table[3])()=
   {
      some_fnc1,   // 00
      some_fnc2,   // 01
      some_fnc3,   // 02
   };
   //здесь опять обработка и далее вызов функции по указателю
   (*fnc_table[Type_F.BYTES.BYTEL])();

}

Это уход от switch-case, когда дойдя до последнего варианта тратится много тактов процессора, а хотелось сразу в зависимости Type_F.BYTES.BYTEL прыгнуть и выполнить нужную строчку. Можно конечно было сделать эти функции и вне основной функции, но тогда при появлении другой подобной "основной" функции но с другим сценарием отработки кодирующего байта Type_F.BYTES.BYTEL пришлось бы городить индивидуальные названия для some_fncХ, читаемость бы была хуже, да и переменные типа temp, которые менялись внутри some_fncХ пришлось бы объявлять глобально, да и называть уникально для каждой основной.
А проблема вот в чем, при отладке заметил, что попадая в read_value() процессор гуляет сперва по массиву fnc_table, потом ещё что-то невообразимо и неописуемое делает и потом таки исполняет код, на тратит на это столько тактов процессора, что весь смысл ухода к указателям на функции теряет смысл и проще сделать все в виде switch-case. Все исполняется нормально, когда функции объявлены вне основной, реально указатель процессора перескакивает на нужную функцию, а тут бардак.
Вопрос это нормально для такого способа объявления функций? Может есть какие-то директивы типа static, inline, и подобные для компилятора, чтобы он помещал объявления some_fncХ и fnc_table в свободное место "кода" до точки входа в функцию read_value() чтобы процессор попадал сразу на "полезный код", а не тупил и не гулял по непонятным строкам, которые ничего конечно не меняют, причем если меняют, то потом процесс перепрыгивает на некие участки кода, которые чистят "следы этого гуляния", но тратят процессорное время? Причем я не хочу включать оптимизацию, я сейчас на этапе отладки, а тут такие непонятные вещи, с оптимизацией вообще черт ногу сломит, что будет показывать.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 11:51:54

Собственно проблема вот в чем, я решил так сказать для ограничения видимости и для использования внутри функций сделать определение функций, указатели на которые я собрал в массив, определить внутри другой функции.
Для ограничения видимости функций есть много штатных методов:
1. static void Func() {} - ограничивает область видимости для Func() файлом, в котором она определена (переменные/константы со static - аналогично);
2. private/protected - ограничивает область доступа для своих членов внутри конкретного экземпляра struct/class (не-static члены) или всего struct/class (static члены);
3. namespace - ограничивает область видимости для переменных/констант/функций своим пространством.
Не надо изобретать деревянный велосипед с квадратными колёсами. Лучше изучите те штатные механизмы, которые есть.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 13:15:51

Собственно проблема вот в чем, я решил так сказать для ограничения видимости и для использования внутри функций сделать определение функций, указатели на которые я собрал в массив, определить внутри другой функции.
Для ограничения видимости функций есть много штатных методов:
1. static void Func() {} - ограничивает область видимости для Func() файлом, в котором она определена (переменные/константы со static - аналогично);
2. private/protected - ограничивает область доступа для своих членов внутри конкретного экземпляра struct/class (не-static члены) или всего struct/class (static члены);
3. namespace - ограничивает область видимости для переменных/констант/функций своим пространством.
Не надо изобретать деревянный велосипед с квадратными колёсами. Лучше изучите те штатные механизмы, которые есть.

Боюсь первый метод не удобен тем, что создавать файл под функцию не очень хочется, хотя это и проще, чем перегружать супердлинными и запутанными именами функций и переменных.
Второй и третий относится как я понял к с++, боюсь кокос у меня такие вещи как namespace и классы не потянет, а со структурами то функции все равно туда не впишешь.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 13:37:55

Per rectum ad astra :)

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 13:52:34

Per rectum ad astra :)

))) надеюсь это "Через тернии к звёздам", а не то что я подумал )))
а если честно, просто я задумался про время исполнения switch, на дизасме показано, что каждый раз проверяется на соответствие case, так что к 100 варианту это будет 100 тактов только одних проверок, а так бы прыг и сразу по адресу выполнил команду, да согласен выглядит криво, зато как работает )))
Если конечно я ошибаюсь, и компилятор там что-то за меня сделает при оптимизации или там проц применит какую-то ноу-хау технологию конвейера или предугадывания и выполнит весь switch за один такт (ну условно один такт) учитывая, что case будет в числе последних, тогда я бы с удовольствием оставил switch-case конструкцию. Просто у меня старая закалка, когда "программист" (хотя меня с натягом можно отнести к этой касте :shock: ) задумывается, что же получается из его кода после компиляции, как это будет работать и как лучше написать код, чтобы это было оптимальным. Это сейчас программисты расслабились, делят спокойно, тк процы стали это делать за 1 такт, обертки используют всевозможные, тк время написания программы стало важнее, чем ее эффективность.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 14:58:51

когда "программист" задумывается, что же получается из его кода после компиляции, как это будет работать и как лучше написать код, чтобы это было оптимальным.
Похвально, но всё должно быть в меру. Ясный и понятный код через switch чаще всего лучше экономии нескольких тактов. Да и компилятору его легче оптимизировать.

И да, это было именно то что ты подумал.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 15:08:09

я извиняюсь, что скажу несколько оторванные от реальности вещи... но когда-то давно компиляторы умели заменять switch, case которого вызывали одиночные однотипные функции, на индексное обращение к массиву функций... неужели сегодня оптимизаторы этот момент не умеют делать?!

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 15:14:36

Именно это я и имел в виду, когда говорил что компилятору легче оптимизировать.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 15:14:44

Goto?
Вообще скорее всего всё соптимизируется нормально. Вы для теста хотя бы -O1 включите и гляньте дизасм. А вложенные функции C не поддерживает в полном смысле этого слова. Поэтому не рекомендуется. Особенно проблемы со скопом возникают.
Опять же никто не мешает запихнуть read_value() и все some_fnc в один файл .c. При этом read_value сделать обычной, а все some_fnc как static inline.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:00:37

а со структурами то функции все равно туда не впишешь.
В смысле?
struct - это то же самое что class. Отличие только в том, что в class доступ к членам по умолчанию - private, а в struct - public.

Добавлено after 3 minutes 32 seconds:
а если честно, просто я задумался про время исполнения switch, на дизасме показано, что каждый раз проверяется на соответствие case, так что к 100 варианту это будет 100 тактов только одних проверок
Не факт. Если у Вас в case-ах будут идти близкие значения (типа case 0, case 1, case 2, ...), то при достаточно большом количестве case умные компиляторы создают таблицу указателей и переходят по ней. При помощи команд TBB/TBH.

Добавлено after 2 minutes 48 seconds:
на индексное обращение к массиву функций... неужели сегодня оптимизаторы этот момент не умеют делать?!
Умеют конечно. Просто ТС видимо никогда не заглядывает в листинг. :dont_know:
И в ARM не нужны никакие функции для этого. Всё проще - система команд позволяет делать переход по таблице смещений к текущему содержимому PC. См. команду TBB/TBH.
Последний раз редактировалось jcxz Чт ноя 21, 2019 16:03:32, всего редактировалось 1 раз.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:01:38

на индексное обращение к массиву функций... неужели сегодня оптимизаторы этот момент не умеют делать?!
Умеют конечно. Просто ТС видимо никогда не заглядывает в листинг. :dont_know:

Пишет что заглядывает, только с отключенной полностью оптимизацией. Конечно совсем без оптимизации будет полный перебор.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:04:59

Пишет что заглядывает, только с отключенной полностью оптимизацией. Конечно совсем без оптимизации будет полный перебор.
У меня IAR уже на уровне оптимизации Medium использует TBB/TBH. На Medium и отлаживаюсь.
А если не использовать оптимизацию вообще, то какой смысл тогда вообще говорить о каких-то тактах??? "Снявши голову о волосах не плачут"...

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:07:37

jcxz, так хотя бы Medium. А у него GCC с -O0, как я догадываюсь (потому что это и означает "оптимизации отключены" в кокосе). Полностью отключена любая оптимизация компилятором. Это уже излишества. Хотя бы -O1 можно включать для отладки вполне.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:09:30

Хотя бы -O1 можно включать для отладки вполне.
На минимуме не будет TBB/TBH. Скорей всего. По-крайней мере в IAR - нету.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:25:03

struct - это то же самое что class.
Знание это на тёмную сторону силы ведёт 8)

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:34:40

я извиняюсь, что скажу несколько оторванные от реальности вещи... но когда-то давно компиляторы умели заменять switch, case которого вызывали одиночные однотипные функции, на индексное обращение к массиву функций... неужели сегодня оптимизаторы этот момент не умеют делать?!

Goto?
Вообще скорее всего всё соптимизируется нормально. Вы для теста хотя бы -O1 включите и гляньте дизасм. А вложенные функции C не поддерживает в полном смысле этого слова. Поэтому не рекомендуется. Особенно проблемы со скопом возникают.
Опять же никто не мешает запихнуть read_value() и все some_fnc в один файл .c. При этом read_value сделать обычной, а все some_fnc как static inline.

Попробовал, у меня аргумент в switch реально имеет разрывы и не малые, короче из меня оптимизатор лучше получился ))) не заменил он на массивы указателей. Может конечно стоит немного упростить задачу оптимизатору, попробую дать как аргумент switch искусственно "enum" подобные данные (итерация). Хотя может это кокос вместе с gcc так работают ((.
ПыСЫ: ну да заменил на -O1, когда данные прям на 1 отличаются, не знал про такую фишку, надо в реале смотреть, у меня case варианты не на столько плотно друг к другу, типа как 0x8080, 0x8280, 0x8480, 0x8482 итд. в хрен пойми какой зависимости. Попробую разбить на подэтапы, дам сперва сравнить по первому байту, там разрывы меньше, а потом уже при попадании по первому, второй искать.
Последний раз редактировалось auric Чт ноя 21, 2019 16:58:06, всего редактировалось 3 раз(а).

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 16:53:05

Кокос - всего лишь IDE, на компилятор она не влияет. Попробуйте тогда бОльший уровень оптимизации. Как уже пишут на -O1 еще может не оптимизировать это дело. -Os или -O3.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 18:21:46

а со структурами то функции все равно туда не впишешь.
В смысле?
struct - это то же самое что class. Отличие только в том, что в class доступ к членам по умолчанию - private, а в struct - public.

Это С++, у меня же Си.

Re: Компоновка и компиляция функций, определенных внутри дру

Чт ноя 21, 2019 23:00:52

Это С++, у меня же Си.
А что Вам мешает использовать си++?

Re: Компоновка и компиляция функций, определенных внутри дру

Пт ноя 22, 2019 08:21:03

Это С++, у меня же Си.
А что Вам мешает использовать си++?

отсутствие поддержки ))
Ответить