Процедура inline и просто процедура

Добрый день.
Немного подвис над ситуацией, может кто прояснит ..
Нужно было некоторые процедуры сделать как inline//
я же правильно понимаю inline процедура - код прописывается вместо вызова процедуры

но судя по данным, процедура что inline , что обычная ничем не отличается , кроме как адресами расположения .. Но и там и там идет переход на процедуру , что не совсем согласуется с inline/// Может я чтото неправильно вызываю…Спасибо
stm32f4 , CUBE IDE , язык СИ

sensor.h и sensor.c с inline

/*
 * sensor.h
 *
 *  Created on: Apr 27, 2025
 *      Author: user
 */

#ifndef SENSOR_H_
#define SENSOR_H_

#ifdef __cplusplus
 extern "C" {
#endif


#include "main.h"




 MAX6675_GetTemperature(float old_t,uint16_t intervals);


 static inline void Enc_Work (void)
 {

	if (master_key == select_start)   
	{
		char tt[10];

		my_profil[pSec].fire_kol = WorkDATA.new_tfire;
		my_profil[pSec].onoff = fire_upd;
		my_profil[pSec + 1].fire_kol = 0;
		my_profil[pSec + 1].onoff = 0;

		WorkDATA.fire_kol = WorkDATA.new_tfire;

		snprintf((char*) tt, 4, "%u%%", WorkDATA.fire_kol);
		LCD_PrintString24(630, 15, GREEN, BLACK, (char*) tt);

		snprintf((char*) tt, 6, "%03u%%", my_profil[pSec].fire_kol);
		LCD_PrintString12(540, 350, GREEN, BLACK, (char*) tt);
		if (my_profil[pSec].onoff == fire_upd)
			LCD_PrintString12(570, 350, GREEN, BLACK, "upd");
		else if (my_profil[pSec].onoff == fire_on)
			LCD_PrintString12(570, 350, GREEN, BLACK, "on");
		else if (my_profil[pSec].onoff == fire_off)
			LCD_PrintString12(570, 350, GREEN, BLACK, "off");

	}

}

.c


/*
 * sensor.c
 *
 *  Created on: Apr 27, 2025
 *      Author: user
 */
#include "sensor.h"


char buff[10] = { 0, };






MAX6675_GetTemperature float old_t, uint16_t intervals) {  // T DRUM

	unsigned long cTime = HAL_GetTick();
	if (cTime - pTime1 >= intervals)
	{
		pTime1 = cTime;
		uint16_t val = MAX6675_Read(1);
		if (val & 0x4)
		{
			TFT_SetTextColor(RED);
			TFT_SetFont(&Font32);
			TFT_String(120, 270, "NO!");
		} else {
		val >>= 3;
		val = MedianFilter1(val * 0.25f);
		snprintf(buff, sizeof(buff), "%03d", val);
//		LCD_PrintString24(440, 200, GREEN, BLACK, (char*) buff);
		TFT_SetTextColor(YELLOW);
		TFT_SetFont(&Font32);
		TFT_String(120, 270, (char*) buff);
		TFT_time(60, 110, time_temper, TFT_WHITE, TFT_BLACK, val);
		}
	}
}

ниже тоже самое , но c обычным вызовом

.h


/*
 * sensor.h
 *
 *  Created on: Apr 27, 2025
 *      Author: user
 */

#ifndef SENSOR_H_
#define SENSOR_H_

#ifdef __cplusplus
 extern "C" {
#endif


#include "main.h"




 MAX6675_GetTemperature(float old_t,uint16_t intervals);


 void Enc_Work (void);

.c

/*
 * sensor.c
 *
 *  Created on: Apr 27, 2025
 *      Author: user
 */
#include "sensor.h"

char buff[10] = { 0, };






MAX6675_GetTemperature (float old_t, uint16_t intervals) {  // T DRUM

	unsigned long cTime = HAL_GetTick();
	if (cTime - pTime1 >= intervals)
	{
		pTime1 = cTime;
		uint16_t val = MAX6675_Read(1);
		if (val & 0x4)
		{
			TFT_SetTextColor(RED);
			TFT_SetFont(&Font32);
			TFT_String(120, 270, "NO!");
		} else {
		val >>= 3;
		val = MedianFilter1(val * 0.25f);
		snprintf(buff, sizeof(buff), "%03d", val);
//		LCD_PrintString24(440, 200, GREEN, BLACK, (char*) buff);
		TFT_SetTextColor(YELLOW);
		TFT_SetFont(&Font32);
		TFT_String(120, 270, (char*) buff);
		TFT_time(60, 110, time_temper, TFT_WHITE, TFT_BLACK, val);
		}
	}
}


void Enc_Work(void) {

	if (master_key == select_start)   //
	{
		char tt[10];

		my_profil[pSec].fire_kol = WorkDATA.new_tfire;
		my_profil[pSec].onoff = fire_upd;
		my_profil[pSec + 1].fire_kol = 0;
		my_profil[pSec + 1].onoff = 0;

		WorkDATA.fire_kol = WorkDATA.new_tfire;

		snprintf((char*) tt, 4, "%u%%", WorkDATA.fire_kol);
		LCD_PrintString24(630, 15, GREEN, BLACK, (char*) tt);

		snprintf((char*) tt, 6, "%03u%%", my_profil[pSec].fire_kol);
		LCD_PrintString12(540, 350, GREEN, BLACK, (char*) tt);
		if (my_profil[pSec].onoff == fire_upd)
			LCD_PrintString12(570, 350, GREEN, BLACK, "upd");
		else if (my_profil[pSec].onoff == fire_on)
			LCD_PrintString12(570, 350, GREEN, BLACK, "on");
		else if (my_profil[pSec].onoff == fire_off)
			LCD_PrintString12(570, 350, GREEN, BLACK, "off");

	}

}

ниже маин он везде одинаковый…

main.c


..........
#include "main.h"
#include "fatfs.h"
#include "i2c.h"
#include "rtc.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "fsmc.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//EEPROM
#include "s_var.h"

#include "fonts.h"
#include "stdio.h"
#include "w25qxx.h"
#include "24LC02.h"
#include "GT911.h"
#include "IMAGE.h"
#include "spi_7796.h"
#include "SSD1963.h"
#include "SSD1963_LL.h"
#include "keys.h"
#include "menu.h"
#include "sensor.h"
#include "PICTURESSD.h"

........................

									if (HAL_GPIO_ReadPin(BT_ENTER_GPIO_Port, BT_ENTER_Pin)== GPIO_PIN_RESET)
		{

			if (cTimes_enter == 0)
				cTimes_enter = HAL_GetTick();
			if (HAL_GetTick() - cTimes_enter > 2000)
			{
				cTimes_enter = 0;
				Enc_Work();   // ДИЗАССЕМБЛИРОВАНИЕ с этой строки  ниже . код что с инлайн , что без один и тотже... разница только в адресах расположения 

			} else
			{
				cTimes_start = 0;				             
			}
		}


..............................

08001a2b: main+1150   bl      0x8009714 <Enc_Work>
08001a2f: main+1154   b.n     0x8001852 <main+678>
08001a31: main+1156   movs    r3, #10
08001a33: main+1158   str     r3, [sp, #4]
08001a35: main+1160   movs    r4, #0
08001a37: main+1162   str     r4, [sp, #0]
08001a39: main+1164   movw    r3, #65535      ; 0xffff
08001a3d: main+1168   movs    r2, #11
08001a3f: main+1170   movs    r1, #110        ; 0x6e
08001a41: main+1172   movs    r0, #60 ; 0x3c
08001a43: main+1174   bl      0x8009d94 <TFT_time>
08001a47: main+1178   ldr     r3, [pc, #100]  ; (0x8001aac <main+1280>)
08001a49: main+1180   strb    r4, [r3, #12]
08001a4b: main+1182   b.n     0x800185e <main+690>
08001a4d: main+1184   ldr     r4, [pc, #112]  ; (0x8001ac0 <main+1300>)
08001a4f: main+1186   ldr     r6, [pc, #116]  ; (0x8001ac4 <main+1304>)
08001a51: main+1188   movs    r2, #0
08001a53: main+1190   mov     r1, r4
08001a55: main+1192   mov     r0, r6
08001a57: main+1194   bl      0x80039e2 <HAL_RTC_GetTime>
08001a5b: main+1198   ldrb    r3, [r4, #1]
08001a5d: main+1200   ldr     r5, [pc, #104]  ; (0x8001ac8 <main+1308>)
08001a5f: main+1202   str     r3, [sp, #0]
08001a61: main+1204   ldrb    r3, [r4, #0]
08001a63: main+1206   ldr     r2, [pc, #104]  ; (0x8001acc <main+1312>)
08001a65: main+1208   movs    r1, #15
08001a67: main+1210   mov     r0, r5
08001a69: main+1212   bl      0x800c614 <snprintf>
08001a6d: main+1216   movs    r2, #0
08001a6f: main+1218   ldr     r1, [pc, #96]   ; (0x8001ad0 <main+1316>)

Компилятор поступает по своему усмотрению. Хочу инлайню, хочу нет.

И если в коде берешь адрес процедуры - директива inline игнорируется

не понял … а где я беру…?

странно конечно получается inline не нужна что-ли

такую здоровую процедуру inline не делают, в этом случае компилятор решает, что вставить call выгоднее, чем подставлять весь этот авнокод. Тем более, оптимизация включена, и скорее всего - по размеру

1 лайк

Вы имеете ввиду , что в ней есть другие вызовы процедур и с точки зрения компилятора это безсмысленно ? Я что-то не подумал про размер .. спасибо

Ты бы почитал чонить про Си наконец-то, там всё написано

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

А вот уник железный говорит:

Спойлер

В языке C компилятор не всегда может сделать функцию inline, даже если указано ключевое слово inline. Вот основные случаи, когда инлайнинг невозможен или затруднён:

1. Рекурсивные функции

  • Если функция вызывает саму себя (прямо или косвенно), компилятор обычно не может её инлайнить полностью, так как это привело бы к бесконечной подстановке.
  • Некоторые компиляторы могут ограниченно инлайнить несколько уровней рекурсии (с оптимизацией -O2 или -O3), но полностью развернуть рекурсию невозможно.

2. Функции с переменным числом аргументов (variadic functions)

  • Например, функции вида printf(const char *fmt, ...) сложно инлайнить из-за их сложной семантики обработки аргументов.

3. Функции, принимающие адрес функции (указатели на функции)

  • Если где-то в коде берётся указатель на функцию, компилятор должен сохранить её как отдельную сущность, даже если она помечена как inline.

4. Функции с динамическим управлением потоком выполнения

  • Функции, содержащие setjmp/longjmp, обычно не инлайнятся, так как это нарушает стек вызовов.

5. Функции, вызываемые через указатели или динамически

  • Если функция вызывается через указатель (func_ptr()), компилятор не всегда может определить, какая именно функция будет вызвана, и поэтому не может её инлайнить.

6. Функции с сложной логикой или большим объёмом кода

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

7. Функции, определённые в другом модуле трансляции (без LTO)

  • Без Link-Time Optimization (LTO) компилятор не может инлайнить функции, определённые в других .c-файлах (если их реализация недоступна в текущей единице трансляции).

8. Виртуальные функции (в C++)

  • Хотя вопрос о C, в C++ виртуальные функции (virtual) обычно не инлайнятся из-за динамической диспетчеризации.

Интересно узнать почему вы захотели эту функцию инлайновой. Техническая необходимость какая.

Нет.

Нормально. Ничего необычного.

Если Вам нужно гарантированно заинлайнить её (и Вы используете GCC) то пользуйтесь атрибутом __always_inline__

4 лайка

Вообще, директива inline будет игнорироваться из-за опции компилятора -Os (по умолчанию в Arduino стоит такая. Оптимизация по размеру.)

Инлайнят, как правило, для скорости. И циклы разворачивают. Но для этого нужно -O2 хотя бы , а лучше -O3

Если же у вас особый случай (редкие случаи, обычно в бутлоадерах или совсем в низкоуровневых драйверах), когда вам во что бы то ни стало надо заинлайнить функцию, используйте такю запист:

int inline __attribute__((always_inline)) myfunc( ... ) {
}

Ну или просто не используйте функцию - переделайте ее в макрос.