Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

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

Вт июн 04, 2019 12:21:18

Добрый день.

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

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

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;
}



Пишу библиотеку. Библиотека создает статический массив, в котором хранит данные. Хочу иметь возможность вызвать функцию этой библиотеки, которая что-то сделает с данными в массиве, а потом запишет в указатель, который я ей передал, указатель на массив. Ну и заодно количество элементов в массиве (но это понятно как сделать).

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

Вт июн 04, 2019 12:27:19

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

static u8 array[10];
u8 * func(u8 *ptr)
{
...
return ptr;
}

u8 *p = func(&array[0]);

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

Вт июн 04, 2019 13:02:55

u8 * func(u8 *ptr);


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

PS. Под статическим я понимаю следующее: он один раз создан и существует на протяжении работы программы, данные в нем могут меняться. Это правильное определение статического?

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

Вт июн 04, 2019 13:14:00

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

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

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

Вт июн 04, 2019 13:28:12

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


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

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

В первом сообщении написал код, где намеренно убрал все звездочки и амперсанды, т.к. не знаю, как их правильно расставить в этом случае.

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

Вт июн 04, 2019 13:34:20

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

Если нужно чтобы функция была void, то возвращать результат из неё можно через указатель на результат. Этот указатель передать как входной аргумент.

Тогда можно принимать от нее ссылки на несколько массивов, переменные и т.п.
Из этой фразы могу предположить что Вы недопонимаете принципов передачи аргументов в функцию и возврата результатов.
В общем случае: если нужно вернуть из функции некий набор параметров, то можно использовать возврат структуры из функции. Либо как сказано выше: в точке вызова передать внутрь функции указатель на такую структуру, в которую и записать результат.

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

Это уже вообще к конкретной функции не относится. А относится к организации алгоритма работы вашей программы.

PS. Под статическим я понимаю следующее: он один раз создан и существует на протяжении работы программы, данные в нем могут меняться. Это правильное определение статического?
Да, примерно так. Кроме того хорошим стилем является: ключевым словом static ограничивать область видимости переменных/функций областью видимости файла.

Добавлено after 1 minute 41 second:
другое дело, что возвращать функция может только один указатель, а если требуется больше - то только через параметры (ну или возвращать структуру с указателями, что, имхо, какой-то изврат).

Это не всегда так. В IAR for ARM например можно с помощью return вернуть из функции два указателя. Да и некоторые другие компиляторы это позволяют.

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

Вт июн 04, 2019 13:41:09

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

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

Вт июн 04, 2019 13:47:57

Если нужно чтобы функция была void, то возвращать результат из неё можно через указатель на результат. Этот указатель передать как входной аргумент.

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

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

Вт июн 04, 2019 13:50:02

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

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

Вт июн 04, 2019 13:53:16

jcxz писал(а):Это не всегда так. В IAR for ARM например можно с помощью return вернуть из функции два указателя.
интересно. и как это выглядит синтаксически? как это вписывается в стандарт Си?
Да очень просто:
Код:
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:

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

Вт июн 04, 2019 13:59:21

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

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

Вт июн 04, 2019 14:27:08

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


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

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;                                   // Присваиваем указателю на указатель указатель ?
}


Где-то еще нужно звездочек доставить, или амперсандов. Я с этим синтаксисом с ума сойду.

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

Вт июн 04, 2019 14:29:33

Код:
uint8_t arr[20];

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


Вызов

Код:
int main(void)
{
    uint8_t *arrPtr;
    Func(arrPtr);
    uint8_t a = arrPtr[19];
}


Исправил :))

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

Вт июн 04, 2019 14:40:34

Солнцеворот писал(а):Я с этим синтаксисом с ума сойду
книги не пробовали читать?
Код:
// библиотека
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 писал(а):Исправил
не успел увидеть, как было, но теперь не правильно

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

Вт июн 04, 2019 15:06:06

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
}

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

Вт июн 04, 2019 15:26:55

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

но я так и не пойму, зачем это делать :(

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

Вт июн 04, 2019 15:29:54

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

Это не свойство оптимизатора. Это так работает компилятор. Всегда. Даже когда оптимизация выключена. И причём думаю, что так должен работать любой компилятор на ARM. Потому что это основано на соглашениях вызова. А эти соглашения они общие для всех компиляторов.
Другими словами: если это было бы не так, то obj-файлы (и библиотеки) скомпилённые разными компиляторами были бы несовместимы. А они совместимы если соответствуют этому соглашению.
И "8 bool" - это совсем не то. Вы внимательнее прочитайте, что я написал. И почитайте про соглашения вызова. По соглашениям вызова для ARM, функция может использовать не более двух регистров R0:R1 для возврата значения. 8 разных значений в двух регистрах не вернуть. Если не говорить об упаковке. но упаковка - это уже не то.
Так что такой возврат - вполне себе штатный способ.

PS: Вобщем - читайте, что такое AEABI. Конкретно раздел "AEABI compliance" мануала на компилятор. Тогда узнаете, что такой способ возврата - стандарт для многих компиляторов.

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

Вт июн 04, 2019 15:52:49

Это не свойство оптимизатора. Это так работает компилятор. Всегда. Даже когда оптимизация выключена. И причём думаю, что так должен работать любой компилятор на ARM.

Сравним с вариантом на плюсах(gcc):
Код:
Pair<void*> func()
{
    void *ptr1 = ...
    void *ptr2 = ...

    return { ptr1, ptr2 };
}

auto [ptr1, ptr2] = func();

С -O2 бинарники получились абсолютно одинаковые, а с -O0 этот вариант меньше на 64 байта...

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

Вт июн 04, 2019 16:00:36

Код:
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];


Зато немного освежили память :)))

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

Вт июн 04, 2019 16:40:46

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();
}
Ответить