|
#define FUNCTION() vs. inline Function(), второе более "модно", а почему? |
|
|
|
Sep 3 2015, 08:13
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 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 Хочу просветления. Или уже...?
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
Sep 3 2015, 08:39
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 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);
|
|
|
|
|
Sep 3 2015, 11:58
|

Гуру
     
Группа: Свой
Сообщений: 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
|
|
|
|
|
Sep 4 2015, 05:39
|
Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462

|
Inline-функции, как было сказано, позволяют сделать меньше ошибок: проверка типов + отладка в пошаговом режиме. Всегда можно вспомнить пример про вызов макроса MAX(a++,  . Как сделать в виде функции макрос ТС зависит от того как определены PORTA, PORTB etc. Скорее всего static inline void GpioConf(GPIO_TypeDef port, uin32_t...) {...}. Не?
|
|
|
|
|
Sep 4 2015, 08:30
|

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

|
QUOTE (ViKo @ Sep 4 2015, 10:37)  Немного некомфортно, что inline функцию нужно вставлять в заголовочный файл *.h, а не в *.c. Чтобы ее можно было использовать в другом файле. А что, с макросами как-то иначе  . Смущает .h? так назовите .c - какие проблемы? QUOTE А сколько переменных можно передать в функцию? ничего не треснет?  Треснет - стек, если его размера не хватит для размещения всех передаваемых переменных.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 4 2015, 08:38
|

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

|
Цитата(zltigo @ Sep 4 2015, 11:30)  А что, с макросами как-то иначе  . Смущает .h? так назовите .c - какие проблемы? Э-э, себя-то не обманешь... include так include. Я не говорю, что прямо воротит, просто не тем цветом в Notepad++ раскрашивает. Цитата Треснет - стек, если его размера не хватит для размещения всех передаваемых переменных. Там не будет использоваться стек, эти переменные заменяются макроопределениями. Код /*! GPIO Mode Type */ typedef enum { MD_IN, //!< Input * MD_GO, //!< General purpose output MD_AF, //!< Alternate function MD_AN //!< Analog } GPIO_MODE_t; и т.д. Я так думаю.
|
|
|
|
|
Sep 4 2015, 09:11
|

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

|
QUOTE (ViKo @ Sep 4 2015, 11:38)  Э-э, себя-то не обманешь... include так include. Я не говорю, что прямо воротит, просто не тем цветом в Notepad++ раскрашивает.  Не понимаю в чем обман. QUOTE Там не будет использоваться стек, эти переменные - макроопределения. Вы это как-бы подумайте, прежде, чем такое писать. Функции глубоко безразлично, она по любому получает переменные в стеке или/и в регистрах.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 4 2015, 09:22
|

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

|
Цитата(zltigo @ Sep 4 2015, 10:11)  Вы это как-бы подумайте, прежде, чем такое писать. Функции глубоко безразлично, она по любому получает переменные в стеке или/и в регистрах. Ну, если функция успешно заинлайнена, зачем ей передавать аргументы (особенно через стек)? Кроме того, хороший компилятор может сам решить, заинлайнить ли ему обычную функцию или нет. Если функция объявлена как static ее может быть выгодно подставить в вызывающую функцию целиком, как раз с целью избавления от передачи лишних аргументов... ТС - вы не меняйте все свои макросы на inline функции, это не одно и то же.. Это разные вещи, и область применения у них разная. Кроме того, с inline функциями могут быть проблемы. Например, криворукий программист объявит inline функцию в заголовке, включит его в несколько модулей и в одном из модулей попытается получить адрес этой функции. В зависимости от кривизны компилятора это может привесли к забавным последствиям.
Сообщение отредактировал CrimsonPig - Sep 4 2015, 09:26
|
|
|
|
|
Sep 4 2015, 09:35
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 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 функция такого не осилит сотворить?
|
|
|
|
|
Sep 4 2015, 09:44
|

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

|
QUOTE (CrimsonPig @ Sep 4 2015, 12:22)  Ну, если функция успешно заинлайнена, зачем ей передавать аргументы (особенно через стек)? В вопросе НЕ БЫЛО про заинлайненую функцию. О передаче арнгментов ЗАИНЛАЙНЕННОЙ функции говорить вообще бесмысленно, ибо нет уже ни функции, ни аргументов. Так-что и ответ не про занлайненную. QUOTE ТС - вы не меняйте все свои макросы на inline функции.... Поддержу.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|