Передать в функцию указатель, а получить указатель на массив

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Передать в функцию указатель, а получить указатель на массив

Сообщение Солнцеворот »

Добрый день.

По идее это возможно, но сложно, и я запутался. Помогите, если кто знает, как такую задачу решить.

Синтаксис неправильный!

main.c :

Код: Выделить всё

uint8_t a;
uint8_t ukazatel_na_massiv;    // Создаем указатель на массив
/* ------ */
func (ukazatel_na_massiv);    // Передаем указатель на массив в функцию, которая вернет нам указатель на реально существующий массив

a = ukazatel_na_massiv[19];    // Забираем последнее значение из массива по указателю на массив, который вернула функция

library.c :

Код: Выделить всё

uint8_t massiv[20];    // Статический массив из 20 элементов

/* ------ */

// Функция возвращает указатель на массив
void func (uint8_t uk){
    uk = massiv;
}

Пишу библиотеку. Библиотека создает статический массив, в котором хранит данные. Хочу иметь возможность вызвать функцию этой библиотеки, которая что-то сделает с данными в массиве, а потом запишет в указатель, который я ей передал, указатель на массив. Ну и заодно количество элементов в массиве (но это понятно как сделать).
Реклама
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение jcxz »

[uquote="Солнцеворот",url="/forum/viewtopic.php?p=3645009#p3645009"]Хочу иметь возможность вызвать функцию этой библиотеки, которая что-то сделает с данными в массиве, а потом запишет в указатель, который я ей передал, указатель на массив. Ну и заодно количество элементов в массиве (но это понятно как сделать).[/uquote]
static u8 array[10];
u8 * func(u8 *ptr)
{
...
return ptr;
}

u8 *p = func(&array[0]);
Реклама
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Солнцеворот »

[uquote="jcxz",url="/forum/viewtopic.php?p=3645013#p3645013"]u8 * func(u8 *ptr);[/uquote]

Спасибо за скорый ответ. Это работает, но не так, как мне надо.
Функция должна быть void, а указатели передаваться в скобках, в качестве параметров функции.
Тогда можно принимать от нее ссылки на несколько массивов, переменные и т.п.
Более того, функция может лишь инициировать выполнение какой-то работы, а результаты нужно считывать по прерыванию или флагу.

PS. Под статическим я понимаю следующее: он один раз создан и существует на протяжении работы программы, данные в нем могут меняться. Это правильное определение статического?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

Солнцеворот писал(а):Функция должна быть void, а указатели передаваться в скобках, в качестве параметров функции.
Тогда можно принимать от нее ссылки на несколько массивов, переменные и т.п.
первая строка не связана со второй: передавать в функцию указатель можно всегда любой хоть на что. другое дело, что возвращать функция может только один указатель, а если требуется больше - то только через параметры (ну или возвращать структуру с указателями, что, имхо, какой-то изврат).

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

Мой уютный бложик... заходите!
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Солнцеворот »

[uquote="ARV",url="/forum/viewtopic.php?p=3645032#p3645032"]лично для меня ваша формулировка задачи остается непонятной - что вы хотите и зачем :([/uquote]

Хочу развязать библиотеку и main.c

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

В первом сообщении написал код, где намеренно убрал все звездочки и амперсанды, т.к. не знаю, как их правильно расставить в этом случае.
Реклама
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение jcxz »

[uquote="Солнцеворот",url="/forum/viewtopic.php?p=3645026#p3645026"]Функция должна быть void, а указатели передаваться в скобках, в качестве параметров функции.[/uquote]
Если нужно чтобы функция была void, то возвращать результат из неё можно через указатель на результат. Этот указатель передать как входной аргумент.

[uquote="Солнцеворот",url="/forum/viewtopic.php?p=3645026#p3645026"]Тогда можно принимать от нее ссылки на несколько массивов, переменные и т.п.[/uquote]Из этой фразы могу предположить что Вы недопонимаете принципов передачи аргументов в функцию и возврата результатов.
В общем случае: если нужно вернуть из функции некий набор параметров, то можно использовать возврат структуры из функции. Либо как сказано выше: в точке вызова передать внутрь функции указатель на такую структуру, в которую и записать результат.

[uquote="Солнцеворот",url="/forum/viewtopic.php?p=3645026#p3645026"]Более того, функция может лишь инициировать выполнение какой-то работы, а результаты нужно считывать по прерыванию или флагу.[/uquote]
Это уже вообще к конкретной функции не относится. А относится к организации алгоритма работы вашей программы.

[uquote="Солнцеворот",url="/forum/viewtopic.php?p=3645026#p3645026"]PS. Под статическим я понимаю следующее: он один раз создан и существует на протяжении работы программы, данные в нем могут меняться. Это правильное определение статического?[/uquote]Да, примерно так. Кроме того хорошим стилем является: ключевым словом static ограничивать область видимости переменных/функций областью видимости файла.

Добавлено after 1 minute 41 second:
[uquote="ARV",url="/forum/viewtopic.php?p=3645032#p3645032"]другое дело, что возвращать функция может только один указатель, а если требуется больше - то только через параметры (ну или возвращать структуру с указателями, что, имхо, какой-то изврат).[/uquote]
Это не всегда так. В IAR for ARM например можно с помощью return вернуть из функции два указателя. Да и некоторые другие компиляторы это позволяют.
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

jcxz писал(а):Это не всегда так. В IAR for ARM например можно с помощью return вернуть из функции два указателя.
интересно. и как это выглядит синтаксически? как это вписывается в стандарт Си?
Солнцеворот писал(а):После выполнения функции у меня из main есть указатели, которые указывают на массивы с данными, которые меня интересуют. И я могу из main этими данными пользоваться, считывать, анализировать и т.д.
бред какой-то. если вы хотите иметь указатели на массивы, что вам мешает просто пользоваться их идентификаторами?! если хотите открыть доступ к static-массиву при помощи функции, зачем его прятать?! ведь этим самым вы перечеркиваете "сокрытие" на 100%...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Солнцеворот »

[uquote="jcxz",url="/forum/viewtopic.php?p=3645037#p3645037"]Если нужно чтобы функция была void, то возвращать результат из неё можно через указатель на результат. Этот указатель передать как входной аргумент.[/uquote]
Вот! именно это мне и нужно. Передаю указатель, как аргумент функции, после выполнения функции по этому указателю читаю данные. Коллега, как?
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

Солнцеворот писал(а):Передаю указатель, как аргумент функции, после выполнения функции по этому указателю читаю данные. Коллега, как?

Код: Выделить всё

void func(int **ptr); // ptr - указатель на указатель
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение jcxz »

[uquote="ARV",url="/forum/viewtopic.php?p=3645043#p3645043"]
jcxz писал(а):Это не всегда так. В IAR for ARM например можно с помощью return вернуть из функции два указателя.
интересно. и как это выглядит синтаксически? как это вписывается в стандарт Си?[/uquote]Да очень просто:

Код: Выделить всё

u64 func()
{
  void *ptr1, *ptr2;
  ...
  return (u32)ptr1 | (u64)(u32)ptr2 << 32;
}
вызов:
u64 q = func();
void *ptr_1 = (void *)(u32)q;
void *ptr_2 = (void *)(u32)(q >> 32);
Указатели вернутся в двух разных регистрах: R0:R1, так что тех операций, что ниже вызова func() в откомпилированном коде не будет.

Я очень часто пользуюсь таким способом. Очень удобно. :)

Вообще где-то в мануалах на какой-то компилятор (IAR for ARM?) встречал утверждение, что если вернуть из функции структуру, размерностью == {int x, y;} (два int-а), то такая структура будет возвращена не через стек (как по дефолту), а в паре регистров R0:R1 уже автоматом. Но моя версия IAR 7.80.4 так не делает почему-то. Может каких-то ключей не хватает.... :dont_know:
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

jcxz писал(а):Я очень часто пользуюсь таким способом. Очень удобно.
вообще говоря, это совсем не то, что вы сказали: это возврат ОДНОГО значения. так ведь и я могу заявить, что командой return (u8)data я возвращаю аж 8 значений bool :)
да и решение основано на свойствах оптимизатора. думаю, в любом компиляторе можно найти подходящий аналог, но я бы так делать не стал.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Солнцеворот »

[uquote="ARV",url="/forum/viewtopic.php?p=3645049#p3645049"]
Солнцеворот писал(а):Передаю указатель, как аргумент функции, после выполнения функции по этому указателю читаю данные. Коллега, как?

Код: Выделить всё

void func(int **ptr); // ptr - указатель на указатель
[/uquote]

Указатель на указатель. А синтаксически как?
Не те данные читает все-равно. Делаю так:

main.c :

Код: Выделить всё

uint8_t **result;   // Указатель на указатель

func(result);         // Вызываю функцию, передаю указатель на указатель

uint8_t r1, r2;      // Контрольные переменные

r1 = result[0];     // Считываю в первую переменную нулевое значение массива
r2 = result[1];     // Считываю во вторую переменную первое значение массива

lib.c :

Код: Выделить всё

uint8_t arr[] = {1,2,3,4,5,6,7,8};    // Указатель на этот массив надо передать

void func (uint8_t **ptr){
    ptr = arr;                                   // Присваиваем указателю на указатель указатель ?
}
Где-то еще нужно звездочек доставить, или амперсандов. Я с этим синтаксисом с ума сойду.
Аватара пользователя
Myp3ik
Мучитель микросхем
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Myp3ik »

Код: Выделить всё

uint8_t arr[20];

void Func(uint8_t *ptr)
{
    ptr = arr;
}
Вызов

Код: Выделить всё

int main(void)
{
    uint8_t *arrPtr;
    Func(arrPtr);
    uint8_t a = arrPtr[19];
}
Исправил :))
Иван Сусанин - первый полупроводник :solder:
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

Солнцеворот писал(а):Я с этим синтаксисом с ума сойду
книги не пробовали читать?

Код: Выделить всё

// библиотека
static int arr[100];

void func(int num, int* *ptr){
   *ptr = &arr[num];
}

// не-библиотека
void func(int num, int* *ptr);

int main(void){
   int *pointer;
   func(10, &pointer);
   // в pointer адрес 10-го элемента массива
   (*pointer)++; // здесь изменяется 10-й элемент "библиотечного" массива
   // вопрос: зачем его прятать в библиотеку, если потом МОЖНО изменить?!
}
Добавлено after 2 minutes 55 seconds:
Re: Передать в функцию указатель, а получить указатель на массив
Myp3ik писал(а):Исправил
не успел увидеть, как было, но теперь не правильно
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Солнцеворот
Встал на лапы
Сообщения: 141
Зарегистрирован: Вт июн 03, 2008 01:39:47

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Солнцеворот »

Myp3ik, нет, так не работает.

ARV, в main мне не нужно изменять данные. Мне их нужно получить.
Спасибо, большое человеческое, работает. Книги читать пробовал. Я просто недостаточно сообразителен для указателей.

Выкладываю рабочий код для тех, кто будет читать эту тему:

main.c :

Код: Выделить всё

uint8_t *result;         // Указатель на массив с результатом выполнения функции

func(&result);           // Вызываем функцию, передаем адрес указателя *result

uint8_t r1, r2, r7;      // Контрольные переменные

r1 = *(result);          // Считываем в переменную нулевой элемент массива (число 11)
r2 = *(result+1);        // Считываем в переменную первый элемент массива (инкрементируем значение указателя и получаем его значение функцией *) (число 22)
r7 = *(result+6);        // Считываем в переменную шестой элемент массива (инкрементируем значение указателя и получаем его значение функцией *) (число 77)

lib.c:

Код: Выделить всё

uint8_t arr[] = {11,22,33,44,55,66,77,88};    // Указатель на этот массив надо передать

void func (uint8_t* *ptr){            // Две звездочки - указатель на указатель
    *ptr = &arr[0];                   // Берем адрес нулевого элемента массива и присваиваем указателю *ptr
}

Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18561
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ARV »

Солнцеворот писал(а):void func (uint8_t* *ptr){            // Две звездочки - указатель на указатель
    *ptr = &arr[0];                   // Берем адрес нулевого элемента массива и присваиваем указателю *ptr
}
в таком случае надо всего-навсего так:

Код: Выделить всё

void func (uint8_t* *ptr){            // Две звездочки - указатель на указатель
    *ptr = arr;                   // Берем адрес массива и присваиваем указателю *ptr
}
но я так и не пойму, зачем это делать :(
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
jcxz
Мудрый кот
Сообщения: 1726
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение jcxz »

[uquote="ARV",url="/forum/viewtopic.php?p=3645056#p3645056"]вообще говоря, это совсем не то, что вы сказали: это возврат ОДНОГО значения. так ведь и я могу заявить, что командой return (u8)data я возвращаю аж 8 значений bool :)
да и решение основано на свойствах оптимизатора. думаю, в любом компиляторе можно найти подходящий аналог, но я бы так делать не стал.[/uquote]
Это не свойство оптимизатора. Это так работает компилятор. Всегда. Даже когда оптимизация выключена. И причём думаю, что так должен работать любой компилятор на ARM. Потому что это основано на соглашениях вызова. А эти соглашения они общие для всех компиляторов.
Другими словами: если это было бы не так, то obj-файлы (и библиотеки) скомпилённые разными компиляторами были бы несовместимы. А они совместимы если соответствуют этому соглашению.
И "8 bool" - это совсем не то. Вы внимательнее прочитайте, что я написал. И почитайте про соглашения вызова. По соглашениям вызова для ARM, функция может использовать не более двух регистров R0:R1 для возврата значения. 8 разных значений в двух регистрах не вернуть. Если не говорить об упаковке. но упаковка - это уже не то.
Так что такой возврат - вполне себе штатный способ.

PS: Вобщем - читайте, что такое AEABI. Конкретно раздел "AEABI compliance" мануала на компилятор. Тогда узнаете, что такой способ возврата - стандарт для многих компиляторов.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Reflector »

[uquote="jcxz",url="/forum/viewtopic.php?p=3645125#p3645125"]Это не свойство оптимизатора. Это так работает компилятор. Всегда. Даже когда оптимизация выключена. И причём думаю, что так должен работать любой компилятор на ARM.[/uquote]
Сравним с вариантом на плюсах(gcc):

Код: Выделить всё

Pair<void*> func()
{
    void *ptr1 = ...
    void *ptr2 = ...

    return { ptr1, ptr2 };
}

auto [ptr1, ptr2] = func();
С -O2 бинарники получились абсолютно одинаковые, а с -O0 этот вариант меньше на 64 байта...
Аватара пользователя
Myp3ik
Мучитель микросхем
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение Myp3ik »

Код: Выделить всё

uint8_t arr[] = { 11, 22, 33, 44, 55, 66, 77, 88 };

void Func(uint8_t **ptr)
{
    *ptr = arr;
}

Код: Выделить всё

    uint8_t *arrPtr;
    
    Func(&arrPtr);
    
    uint8_t r1 = arrPtr[0];
    uint8_t r2 = arrPtr[1];
    uint8_t r7 = arrPtr[6];
Зато немного освежили память :)))
Иван Сусанин - первый полупроводник :solder:
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Передать в функцию указатель, а получить указатель на ма

Сообщение ПростоНуб »

Reflector, , исходя из того, что функция в C может возвращать структуру (не указатель на структуру, а именно структуру), то вернуть она может таким образом произвольное количество данных, причем даже различного типа.
В данном случае, использование структуры тоже упростило бы код.
Для GCC структуры размером до N байт (N*8 бита) могут возвращаться в регистрах. N - максимальная длина в байтах целого числа, поддерживаемого на целевой платформе. Может быть 4, 8, 16.

Добавлено after 16 minutes 58 seconds:
Re: Передать в функцию указатель, а получить указатель на массив

Код: Выделить всё

typedef struct pointers_pair_st {
  uint8_t *pair[2];
} pointers_pair_t;

static uint8_t arr1[] = {11,22,33,44,55,66,77,88};
static uint8_t arr2[] = {1,2,3,4,5,6,7,8};

pointers_pair_t func(void){
  pointers_pair_t return_value = {arr1, arr2};
  return(return_value);
}

void main(void)
{
  pointers_pair_t my_pair;
  
  my_pair=func();
}
Ответить

Вернуться в «ARM»