реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> #define FUNCTION() vs. inline Function(), второе более "модно", а почему?
ViKo
сообщение Sep 3 2015, 08:13
Сообщение #1


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



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

К примеру, задать бит в порту можно с одинаковым успехом обоими вариантами. Для единообразия пошел по второму:
Код
__forceinline void FpRq_off(void)
{
  GPIOA->BSRR = FPRQ_H;
}

Но, скажем, функцию задержки, вычисляющую начальное значение счетчика в зависимости от времени, делаю комбинацией макрофункции со встроенной функцией.

Код
#define DELAY(VALUE, UNIT)    \
  DelayFourCycles(((VALUE) * UNIT * (SYSCLK / 1000000) + 3999) / 4000)

#pragma push
#pragma O3
__forceinline void DelayFourCycles(uint32_t FC)
{
__asm {
LOOP:
    SUBS FC, FC, #1
    BNE LOOP
  }
}
#pragma pop


Хочу просветления. Или уже...? rolleyes.gif
Go to the top of the page
 
+Quote Post
dimka76
сообщение Sep 3 2015, 08:25
Сообщение #2


developer
****

Группа: Свой
Сообщений: 902
Регистрация: 12-04-06
Из: Казань
Пользователь №: 16 032



Например с точки зрения удобства.
С инлайн фукциями проще искать ошибки.
Например если у вас вложенные макросы и внутри какого-то их них ошибка, то компилятор не скажет где точно она, а скажет ищите где-то в макросе.
Или например при отладке при пошаговом проходе нельзя залезть внутрь макроса, а внутрь функции можно.

Может конечно есть и еще что-то более существенное, но я не знаю.


--------------------
Все может быть и быть все может, и лишь того не может быть-чего уж точно быть не может, хотя..и это может быть.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 3 2015, 08:39
Сообщение #3


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Еще один пример. Я не представляю, как сделать это в виде функции.
CODE
#define GPIO_CONF(PORT, \
MD00, OT00, SP00, PL00, AF00, \
MD01, OT01, SP01, PL01, AF01, \
MD02, OT02, SP02, PL02, AF02, \
MD03, OT03, SP03, PL03, AF03, \
MD04, OT04, SP04, PL04, AF04, \
MD05, OT05, SP05, PL05, AF05, \
MD06, OT06, SP06, PL06, AF06, \
MD07, OT07, SP07, PL07, AF07, \
MD08, OT08, SP08, PL08, AF08, \
MD09, OT09, SP09, PL09, AF09, \
MD10, OT10, SP10, PL10, AF10, \
MD11, OT11, SP11, PL11, AF11, \
MD12, OT12, SP12, PL12, AF12, \
MD13, OT13, SP13, PL13, AF13, \
MD14, OT14, SP14, PL14, AF14, \
MD15, OT15, SP15, PL15, AF15); \
GPIO##PORT->MODER = ( \
MD00 << 0 | MD01 << 2 | MD02 << 4 | MD03 << 6 | \
MD04 << 8 | MD05 << 10 | MD06 << 12 | MD07 << 14 | \
MD08 << 16 | MD09 << 18 | MD10 << 20 | MD11 << 22 | \
MD12 << 24 | MD13 << 26 | MD14 << 28 | (uint32_t)MD15 << 30); \
GPIO##PORT->OTYPER = ( \
OT00 << 0 | OT01 << 1 | OT02 << 2 | OT03 << 3 | \
OT04 << 4 | OT05 << 5 | OT06 << 6 | OT07 << 7 | \
OT08 << 8 | OT09 << 9 | OT10 << 10 | OT11 << 11 | \
OT12 << 12 | OT13 << 13 | OT14 << 14 | (uint32_t)OT15 << 15); \
GPIO##PORT->OSPEEDR = ( \
SP00 << 0 | SP01 << 2 | SP02 << 4 | SP03 << 6 | \
SP04 << 8 | SP05 << 10 | SP06 << 12 | SP07 << 14 | \
SP08 << 16 | SP09 << 18 | SP10 << 20 | SP11 << 22 | \
SP12 << 24 | SP13 << 26 | SP14 << 28 | (uint32_t)SP15 << 30); \
GPIO##PORT->PUPDR = ( \
PL00 << 0 | PL01 << 2 | PL02 << 4 | PL03 << 6 | \
PL04 << 8 | PL05 << 10 | PL06 << 12 | PL07 << 14 | \
PL08 << 16 | PL09 << 18 | PL10 << 20 | PL11 << 22 | \
PL12 << 24 | PL13 << 26 | PL14 << 28 | (uint32_t)PL15 << 30); \
GPIO##PORT->AFR[0] = ( \
AF00 << 0 | AF01 << 4 | AF02 << 8 | AF03 << 12 | \
AF04 << 16 | AF05 << 20 | AF06 << 24 | (uint32_t)AF07 << 28); \
GPIO##PORT->AFR[1] = ( \
AF08 << 0 | AF09 << 4 | AF10 << 8 | AF11 << 12 | \
AF12 << 16 | AF13 << 20 | AF14 << 24 | (uint32_t)AF15 << 28);
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Sep 3 2015, 09:19
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(ViKo @ Sep 3 2015, 09:13) *
Собственно, весь вопрос в заголовке темы. Помню фразы, что в C++ роль макроопределений много меньше, чем в C. Стало быть, надо ориентироваться на inline функции?

__forceinline void DelayFourCycles(uint32_t FC)
{
__asm {
LOOP:
SUBS FC, FC, #1
BNE LOOP
}
}


Ваша функция задержки на пустом цикле таки правильно работает с I-cache и branch prediction ?
Go to the top of the page
 
+Quote Post
_4afc_
сообщение Sep 3 2015, 09:34
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 262
Регистрация: 13-10-05
Из: Санкт-Петербург
Пользователь №: 9 565



В Watcom C inline не всегда инлайнились если inline вызывал inline, глубину раскручивания вложенных inline можно было регулировать прагмами:

#pragma inline_recursion (on|off)
#pragma inline_depth 1..xxx
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 3 2015, 10:31
Сообщение #6


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(CrimsonPig @ Sep 3 2015, 12:19) *
Ваша функция задержки на пустом цикле таки правильно работает с I-cache и branch prediction ?

Регистрик декрементируется за 1 такт, счетчичек команд скачет за 3 такта. Думаете, с кэша начнет за полтакта все делать?
И, вообще, у меня кэша нема.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Sep 3 2015, 11:58
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (dimka76 @ Sep 3 2015, 11:25) *
С инлайн фукциями проще искать ошибки.

Точнее СЛОЖНЕЕ сделать ошибки. Других причин нет. Но для простейших задач все инлайновские обертки ничего, кроме кучи мусора для глаз, не дают.


QUOTE (_4afc_ @ Sep 3 2015, 12:34) *
В Watcom C...

Ого! Кто-то, кроме меня, еще помнит и пользует Watcom? Я до сих пор массу всяких утилиток на Watcom пишу - традиция, да и под Linux сразу из под Win собираются, ибо линукс дано похерил, но иногда нужно бывает.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Sep 4 2015, 05:39
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Inline-функции, как было сказано, позволяют сделать меньше ошибок: проверка типов + отладка в пошаговом режиме. Всегда можно вспомнить пример про вызов макроса MAX(a++, cool.gif.

Как сделать в виде функции макрос ТС зависит от того как определены PORTA, PORTB etc. Скорее всего static inline void GpioConf(GPIO_TypeDef port, uin32_t...) {...}. Не?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 4 2015, 07:37
Сообщение #9


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Valentine Loginov @ Sep 4 2015, 08:39) *
Как сделать в виде функции макрос ТС зависит от того как определены PORTA, PORTB etc. Скорее всего static inline void GpioConf(GPIO_TypeDef port, uin32_t...) {...}. Не?

Немного некомфортно, что inline функцию нужно вставлять в заголовочный файл *.h, а не в *.c. Чтобы ее можно было использовать в другом файле.
А сколько переменных можно передать в функцию? ничего не треснет? biggrin.gif
Go to the top of the page
 
+Quote Post
zltigo
сообщение Sep 4 2015, 08:30
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (ViKo @ Sep 4 2015, 10:37) *
Немного некомфортно, что inline функцию нужно вставлять в заголовочный файл *.h, а не в *.c. Чтобы ее можно было использовать в другом файле.

А что, с макросами как-то иначе sm.gif. Смущает .h? так назовите .c - какие проблемы?
QUOTE
А сколько переменных можно передать в функцию? ничего не треснет? biggrin.gif

Треснет - стек, если его размера не хватит для размещения всех передаваемых переменных.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 4 2015, 08:38
Сообщение #11


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(zltigo @ Sep 4 2015, 11:30) *
А что, с макросами как-то иначе sm.gif. Смущает .h? так назовите .c - какие проблемы?

Э-э, себя-то не обманешь... include так include. Я не говорю, что прямо воротит, просто не тем цветом в Notepad++ раскрашивает. rolleyes.gif
Цитата
Треснет - стек, если его размера не хватит для размещения всех передаваемых переменных.

Там не будет использоваться стек, эти переменные заменяются макроопределениями.
Код
/*! GPIO Mode Type */
typedef enum {
  MD_IN,            //!< Input *
  MD_GO,            //!< General purpose output
  MD_AF,            //!< Alternate function
  MD_AN                //!< Analog  
} GPIO_MODE_t;
и т.д.

Я так думаю.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Sep 4 2015, 09:11
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (ViKo @ Sep 4 2015, 11:38) *
Э-э, себя-то не обманешь... include так include. Я не говорю, что прямо воротит, просто не тем цветом в Notepad++ раскрашивает. rolleyes.gif

Не понимаю в чем обман.
QUOTE
Там не будет использоваться стек, эти переменные - макроопределения.

Вы это как-бы подумайте, прежде, чем такое писать. Функции глубоко безразлично, она по любому получает переменные в стеке или/и в регистрах.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Sep 4 2015, 09:22
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(zltigo @ Sep 4 2015, 10:11) *
Вы это как-бы подумайте, прежде, чем такое писать. Функции глубоко безразлично, она по любому получает переменные в стеке или/и в регистрах.


Ну, если функция успешно заинлайнена, зачем ей передавать аргументы (особенно через стек)?
Кроме того, хороший компилятор может сам решить, заинлайнить ли ему обычную функцию или нет. Если функция объявлена как static ее может быть выгодно подставить в вызывающую функцию целиком, как раз с целью избавления от передачи лишних аргументов...

ТС - вы не меняйте все свои макросы на inline функции, это не одно и то же.. Это разные вещи, и область применения у них разная. Кроме того, с inline функциями могут быть проблемы. Например, криворукий программист объявит inline функцию в заголовке, включит его в несколько модулей и в одном из модулей попытается получить адрес этой функции. В зависимости от кривизны компилятора это может привесли к забавным последствиям.

Сообщение отредактировал CrimsonPig - Sep 4 2015, 09:26
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 4 2015, 09:35
Сообщение #14


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(zltigo @ Sep 4 2015, 12:11) *
Функции глубоко безразлично, она по любому получает переменные в стеке или/и в регистрах.

Сейчас макрофункция инициализации порта компилируется в ~14 команд (+ память для констант):
CODE

inline void GPIO_init(void)
{
/* Биты 0..7 порта A используются для чтения RL, нужно подтянуть к GND */
GPIO_CONF(A,
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 0: RL0
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 1: RL1
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 2: RL2
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 3: RL3
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 4: RL4
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 5: RL5
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 6: RL6
MD_IN, OT_PP, SP_LO, PL_PD, AF_00, // 7: RL7
MD_AF, OT_PP, SP_ME, PL_NP, AF_02, // 8: TIM1_CH1 - FCAL
MD_AF, OT_PP, SP_HI, PL_NP, AF_01, // 9: USART1_TX -> FPRX
MD_AF, OT_PP, SP_LO, PL_NP, AF_01, // 10: USART1_RX <- FPTX
MD_GO, OT_PP, SP_ME, PL_NP, AF_00, // 11: L3V
MD_GO, OT_PP, SP_ME, PL_NP, AF_00, // 12: L12V
MD_AF, OT_PP, SP_ME, PL_NP, AF_00, // 13: SWDIO
MD_AF, OT_PP, SP_ME, PL_NP, AF_00, // 14: SWCLK
MD_GO, OT_PP, SP_HI, PL_NP, AF_00); // 15: FREQ-


CODE

GPIO_init PROC
;;;194 */
;;;195 inline void GPIO_init(void)
000000 2009 MOVS r0,#9
;;;196 {
;;;197 /* Биты 0..7 порта A используются для чтения RL, нужно подтянуть к GND */
;;;198 GPIO_CONF(A,
000002 4912 LDR r1,|L80.76|
000004 06c0 LSLS r0,r0,#27
000006 6001 STR r1,[r0,#0]
000008 2200 MOVS r2,#0
00000a 8082 STRH r2,[r0,#4]
00000c 4910 LDR r1,|L80.80|
00000e 6081 STR r1,[r0,#8]
000010 4910 LDR r1,|L80.84|
000012 60c1 STR r1,[r0,#0xc]
000014 6202 STR r2,[r0,#0x20]
000016 21ff MOVS r1,#0xff
000018 3113 ADDS r1,r1,#0x13
00001a 6241 STR r1,[r0,#0x24]

И что, inline функция такого не осилит сотворить? 01.gif
Go to the top of the page
 
+Quote Post
zltigo
сообщение Sep 4 2015, 09:44
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (CrimsonPig @ Sep 4 2015, 12:22) *
Ну, если функция успешно заинлайнена, зачем ей передавать аргументы (особенно через стек)?

В вопросе НЕ БЫЛО про заинлайненую функцию. О передаче арнгментов ЗАИНЛАЙНЕННОЙ функции говорить вообще бесмысленно, ибо нет уже ни функции, ни аргументов.
Так-что и ответ не про занлайненную.
QUOTE
ТС - вы не меняйте все свои макросы на inline функции....

Поддержу.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 4 2015, 09:50
Сообщение #16


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(zltigo @ Sep 4 2015, 12:44) *
В вопросе НЕ БЫЛО про заинлайненую функцию. О передаче арнгментов ЗАИНЛАЙНЕННОЙ функции говорить вообще бесмысленно, ибо нет уже ни функции, ни аргументов.
Так-что и ответ не про занлайненную.

Вся тема посвящена inline функциям.

Цитата(CrimsonPig @ Sep 4 2015, 12:22) *
это не одно и то же.. Это разные вещи, и область применения у них разная.

Вот об этом и прошу высказаться.
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Sep 4 2015, 09:51
Сообщение #17


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(ViKo @ Sep 4 2015, 10:35) *
Сейчас макрофункция инициализации порта компилируется в ~14 команд (+ память для констант):


Ну так попробуйте и нам расскажите sm.gif
Не, понятно, что вы дочитали книжку до описания inline функций и пытаетесь всунуть их теперь куда нужно и не нужно. Не волнуйтесь, все этим занимаются по началу sm.gif
Хотите еще занятие на полгода примерно ? Почитайте про шаблоны в Ц++ и попытайтесь переписать свой код инициализации на рекурсивных шаблонах и прочей радости sm.gif
Это можно сделать.. некорорые даже это делают. Нормально получается у единиц, и никто не пользуется в результате sm.gif
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 4 2015, 09:55
Сообщение #18


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(CrimsonPig @ Sep 4 2015, 12:51) *
Ну так попробуйте и нам расскажите sm.gif
Не, понятно, что вы дочитали книжку до описания inline функций и пытаетесь всунуть их теперь куда нужно и не нужно. Не волнуйтесь, все этим занимаются по началу sm.gif

Я не волнуюсь. Вам же повторю "Если нечего сказать, не говори ничего." biggrin.gif
Go to the top of the page
 
+Quote Post
CrimsonPig
сообщение Sep 4 2015, 10:07
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502



Цитата(ViKo @ Sep 4 2015, 10:55) *
Я не волнуюсь. Вам же повторю "Если нечего сказать, не говори ничего." biggrin.gif


Спасибо вам за совет. Идите.... в гугль, там вам место sm.gif
Go to the top of the page
 
+Quote Post
zltigo
сообщение Sep 4 2015, 10:18
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (ViKo @ Sep 4 2015, 12:35) *
И что, inline функция такого не осилит сотворить? 01.gif

Или да, или нет. Завистит от того, насколько компилятор сможет перелопатить с слепить воедино. В идеале без разницы. Реальность надо смотреть.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Sep 6 2015, 18:46
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(zltigo @ Sep 4 2015, 13:18) *
В идеале без разницы. Реальность надо смотреть.

На фоне полной оптимизации что идеал, что реальность одинаково, я бы сказал, непредсказуемы.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 7 2015, 09:03
Сообщение #22


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



А я проверил. Всё то же, inline функция GPIO_conf(...) с 80 переменными скомпилировалась в те же 14-16 команд. С точностью до байта не проверял, потому что только для одного порта запустил. Кейл - молоток!
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Sep 10 2015, 07:02
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Если много аргументов - передавайте указатель на структуру. Современные компиляторы и это нормально скомпилируют (лучше проверить конечно), зато выглядеть будет чуть симпатичнее.
Код
typedef struct { ...  } InitConfig;
static inline void Init(InitConfig const *config) {}

...

InitConfig const init_config = { ... };
Init(&init_config);
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 30th July 2025 - 00:01
Рейтинг@Mail.ru


Страница сгенерированна за 0.0159 секунд с 7
ELECTRONIX ©2004-2016