Возврат данных из функции

Проверяем в Atollic True Studio , gcc для STM32F205 :

Возврат данных из функции

Сразу для понимания пример :

uint8_t myFunction(....)
{
  ......
  return 123;
}
main()
{
  uint8_t ret = myFunction(...);
  // равносильно в буквальном смысле
  uint8_t ret = 123; 

То есть тот тип данных , что возвращается из функции создается в основной программе просто как переменная.

Поэтому возвращая из функции массивы и другие объемные данные надо понимать , что вы расходуете память.


Возврат указателя из функции через return

uint8_t str[]="1234567"; 			
// --> func str=0x2000016c '1234567' работает

static uint8_t str[]="1234567";  		
// --> func str=0x2000016c '1234567' работает

uint8_t * func(uint16_t ii)
{
    uint8_t str[]="1234567";    		
    //  --> func str=0x20001238 '1234567' НЕ РАБОТАЕТ

    static uint8_t str[]="1234567"; 	
    //  --> func str=0x2000016c '1234567' работает

    uint8_t *str="1234567";   		
    //  --> func str=0x8010280 '1234567' работает

    printf("func str=%p '%s'\n",str,str);
    return str;
}

void main()
{
	uint8_t * pStr= func(456);
	printf("pStr='%s'\n",pStr);
...
HardFault ! для uint8_t str[]="1234567" (внутри функции);

uint8_t str[] (внутри функции) - размещение в стеке
uint8_t *str размещение во флеше (это где константные данные и код хранится)

static uint8_t str[](вне / в функции) , uint8_t str[] (вне функции) - в статической памяти SRAM , она же куча, (эта та , которая очищается после выключения)

Выводы

Возврат указателя из функции возможен , но главный вопрос : указатель на кого ? . То есть где находится указуемый ? : если в стеке то нельзя, если в куче и флэше , то можно.

Возврат указателя из функции через параметр передаваемый в функцию

Это возможно только если передавать двойной указатель ** !


uint8_t str[]="1234567"; // 20000000  - это куча
uint8_t* str="1234567"; // 0x8001cec  - это flash .rodata

void func( uint8_t **pp)
{
	printf("func pp=%p 0x%x *pp=%x\n" , pp , pp, *pp); // func pp=0x2001ffec 0x2001ffec *pp=f

	*pp=str; // так можно оказывается

	printf("func pp=%p 0x%x *pp=%x\n" , pp , pp, *pp); // func pp=0x2001ffec 0x2001ffec *pp=20000000

	// сам параметр pp (двойной указатель) размещен в стеке (pp=0x2001ffec) 
        // и он будет затерт при выходе из функции
        // а его значение *pp - это указатель на p в main (его значение было 0xf и ему поменяли на 0x20000000) !
	return;
}

int main(void)
{
	uint8_t *p=0x0f;
	uint8_t *pp=&p;

	printf("p=%p 0x%x pp=%p 0x%x\n" , p , p , pp , pp); //p=0xf 0xf pp=0x2001ffec 0x2001ffec

	func(pp);

	printf("p=%p 0x%x pp=%p 0x%x\n" , p , p , pp , pp);  // p=0x20000000 0x20000000 pp=0x2001ffec 0x2001ffec

	printf("p=%p = '%s' \n" , p , p); // p=0x20000000 = '1234567'


Если надо вернуть несколько указателей из функции

Тогда можно тупо возвращать по return структуру с нужным количеством параметров.

И по-видимому это единственный правильный метод.