Jump to content

    
Dec_NN

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

Recommended Posts

STM32. STM32CubeIde.

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

 

void func1(uint8_t *buf_1);
void func2(uint8_t *buf_2);

uint8_t my_array[50];

void main
{
  func1(my_array);
}

void func1(uint8_t *buf_1)
{
  memset(buf_1, 0x00, sizeof(buf_1)); // Здесь все нормально, все элементы my_array устанавливаются в 0
  func2(buf_1);
}

void func2(uint8_t *buf_2)
{
  memset(buf_2, 0xFF, sizeof(buf_2)); // Здесь только первые 4 элемента my_array устанавливаются в FF, остальные не модифицируются
}

 

Также компилятор выдает warning: argument to 'sizeof' in 'memset' call is the same expression as the destination; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]
 
Понимаю, что как-то ошибочно ссылаюсь на массив при вызове второй функции, но не понимаю как сделать правильно.

 

Share this post


Link to post
Share on other sites
2 minutes ago, Dec_NN said:

Здесь все нормально, все элементы my_array устанавливаются в 0

Нет, не нормально. sizeof(buf_1) возвращает размер указателя, а не массива.

А элементы и так инициализированы в 0.

Share this post


Link to post
Share on other sites
6 минут назад, Dec_NN сказал:


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

 

void main
{
  func1(my_array, sizeof(my_array));
}

 

void func1(uint8_t *buf_1,  uint32_t size)
{
  memset(buf_1, 0x00, size); // Здесь все нормально, все элементы my_array устанавливаются в 0
  func2(buf_1, 4);
}

void func2(uint8_t *buf_2,  uint32_t size)
{
  memset(buf_2, 0xFF, size); // Здесь только первые 4 элемента my_array устанавливаются в FF, остальные не модифицируются
}

Share this post


Link to post
Share on other sites
37 minutes ago, Dec_NN said:
35 minutes ago, aaarrr said:

Нет, не нормально. sizeof(buf_1) возвращает размер указателя, а не массива.

А элементы и так инициализированы в 0.

Действительно. Вы правы.

 

25 minutes ago, HardEgor said:

 

void main
{
  func1(my_array, sizeof(my_array));
}

 

void func1(uint8_t *buf_1,  uint32_t size)
{
  memset(buf_1, 0x00, size); // Здесь все нормально, все элементы my_array устанавливаются в 0
  func2(buf_1, 4);
}

void func2(uint8_t *buf_2,  uint32_t size)
{
  memset(buf_2, 0xFF, size); // Здесь только первые 4 элемента my_array устанавливаются в FF, остальные не модифицируются
}

Огромное спасибо. Теперь все понял. Проблема не в передаче указателя, а в работе функции sizeof.

func2(buf_1, 4) из вашего примера заменил на func2(buf_1, size);

Share this post


Link to post
Share on other sites
3 часа назад, Dec_NN сказал:

Проблема не в передаче указателя, а в работе функции sizeof.

Проблема в том, что вы изначально не поняли, что передавая функции указатель на объект, ей надо передать и количество этих объектов, если хотите работать с массивом этих объектов. Откуда функция узнает количество элементов в массиве, имея только указатель на один из его элементов? Код в теле функции не отличает указатель на объект от указателя на массив объектов. Для него они абсолютно одинаковы. Не просто так стандартные функции memset, memcpy, memcmp имеют параметр - размер объекта в байтах.

Share this post


Link to post
Share on other sites

Я сделал бы так:
 

void func1(uint8_t *buf_1);
void func2(uint8_t *buf_2);

#define SIZE_BUF 50

uint8_t my_array[SIZE_BUF];

void main
{
  func1(my_array);
}

void func1(uint8_t *buf_1)
{
  memset(buf_1, 0x00, sizeof(uint8_t) * SIZE_BUF);
  func2(buf_1);
}

void func2(uint8_t *buf_2)
{
  memset(buf_2, 0xFF, sizeof(uint8_t) * SIZE_BUF);
}

Передача нескольких параметров в функцию - это дурной тон. В данном случае только два, что ещё терпимо. А если их несколько, то лучше передать указатель на структуру.

Share this post


Link to post
Share on other sites
19 минут назад, ДЕЙЛ сказал:

Передача нескольких параметров в функцию - это дурной тон.

А пруфы будут?

Цитата

В данном случае только два, что ещё терпимо.

Передаю 4, уже не терпимо?:crazy:

Цитата

А если их несколько, то лучше передать указатель на структуру.

Чем лучше? Синтаксически - да. По быстроте ~нет.

Share this post


Link to post
Share on other sites
4 minutes ago, Arlleex said:

А пруфы будут?

Передаю 4, уже не терпимо?:crazy:

Чем лучше? Синтаксически - да. По быстроте ~нет.

Параметр передаётся обычно через регистр процессора, число которых ограничено. Если параметров будет слишком много, то передаваться они будут через обычную память, что замедлит выполнение программы. Ещё и размер памяти программы увеличивается при неоптимальном коде.

Share this post


Link to post
Share on other sites
1 минуту назад, ДЕЙЛ сказал:

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

А Ваша структура, указатель на которую Вы хотите потом передать аргументом, память не требует?

Share this post


Link to post
Share on other sites
4 minutes ago, Arlleex said:

А Ваша структура, указатель на которую Вы хотите потом передать аргументом, память не требует?

Есть структура из 100 параметров.

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

При вызове функции с передачей указателя никакого дополнительного копирования не потребуется.

 

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

 

Share this post


Link to post
Share on other sites
3 минуты назад, ДЕЙЛ сказал:

При вызове функции с передачей указателя никакого дополнительного копирования не потребуется.

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

Share this post


Link to post
Share on other sites

Сколько способов, столько и мнений. В каждой ситуации идеальным будет компромиссное решение. Это как написать "Hello world" разными способами.

 

Share this post


Link to post
Share on other sites
1 час назад, ДЕЙЛ сказал:

memset(buf_1, 0x00, sizeof(uint8_t) * SIZE_BUF);

А чего не так

memset(buf_1, 0x00, sizeof(my_array));

???

50 минут назад, ДЕЙЛ сказал:

то замедлит выполнение программы.

Вы так можете говорить только после изучения листингов компилятора. Чего он там намудрит/наоптимизирует - совершенно неочевидно без полного примера кода.

38 минут назад, ДЕЙЛ сказал:

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

Простите, но вы разарботчиков компиляторов совсем не уважаете? Оптимизаторы нынче весьма лихие, и копирование может не понадобится. Однако, если локальная переменная, а именно таковой является аргумент функции, переданный по значинию, меняется, то без копирования не обойтись.

22 минуты назад, ДЕЙЛ сказал:

Это как написать "Hello world" разными способами.

Правда реальные программы координально отличаются от "Hello World". В общем, изучайте стандарты языка. Тогда и говорить дальше можно будет)

50 минут назад, ДЕЙЛ сказал:

Параметр передаётся обычно через регистр процессора, число которых ограничено.

А если компилятор заинлайнит функцию?

Edited by MrBearManul

Share this post


Link to post
Share on other sites
11 minutes ago, MrBearManul said:

А чего не так


memset(buf_1, 0x00, sizeof(my_array));

???

Лучше перебдеть и накодить под самый тупой компилятор. my_array может восприняться как указатель на начало массива.

11 minutes ago, MrBearManul said:

Вы так можете говорить только после изучения листингов компилятора. Чего он там намудрит/наоптимизирует - совершенно неочевидно без полного примера кода.

Простите, но вы разарботчиков компиляторов совсем не уважаете? Оптимизаторы нынче весьма лихие, и копирование может не понадобится. Однако, если локальная переменная, а именно таковой является аргумент функции без ссылки, меняется, то без копирования не обойтись.

Правда реальные программы координально отличаются от "Hello World". 

если компилятор заинлайнит функцию?

Упрощение жизни компилятору кашу не испортит.  Компиляторы не боги и тоже делают ошибки, для обхода которых иногда приходится менять код алгоритма.

12 minutes ago, MrBearManul said:

 В общем, изучайте стандарты языка. Тогда и говорить дальше можно будет)

Пока только 6 лет непрерывного кодинга на Си, но обязательно изучу язык!

Edited by ДЕЙЛ

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.