Использовать обратные вызовы в ардуино с указателями на функции (будут ли функции сохраняться в памяти?)

c++ callbacks lambda

Когда я изучал Arduino (микроконтроллеры, C++ и т. д.), я понял, что память очень ограничена. Я уже понимаю, как работает память, когда речь идет о переменных. Но я не понимаю, как работает память, когда речь идет о функциях. Поскольку я поддерживаемый разработчик, я стараюсь держаться подальше от прерываний и вместо этого использовать функции обратного вызова. Еще одна причина, по которой я предпочитаю использовать функции обратного вызова, заключается в том, что мне нравится интегрированная среда разработки Visual Studio. Я создаю свою основную функциональность любого проекта, который я создаю, на проекте C++, предназначенном для Windows. Как только мои алгоритмы/логика работают так, как я хочу, я ссылаюсь на эти библиотеки на Arduino.

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

/* MyRadioLibrary.h */
// Я не включаю весь код `MyRadioLibrary`, потому что это затрудняет
// понять, о чем я спрашиваю. Вместо этого я постараюсь использовать много псевдокода. Разрешите
// узнайте, хотите ли вы, чтобы я опубликовал код в качестве редактирования.

class MyRadioLibrary
{

public:

    static void SendEvent(int typeOfEvent, void(*onEventCompleted)(bool x))
    {
        // у меня есть массив указателей на функции
        void(*onEventCompletedBuffer[10])(bool x);

        // Я ставлю это событие в очередь с помощью вспомогательного класса очереди

        // Отправить событие ....

        // СЕЙЧАС ЖДЕМ ОТВЕТА, ПОСКОЛЬКУ ОБРАТНЫЙ ВЫЗОВ УЖЕ СОХРАНЕН
    }

    static void loop() {

         // прослушивание радиосообщений
         if(radio.available()){
                // получаем ответ
                // удалить указатель из очереди для обратного вызова
                // выполнить обратный вызов
          }   
                    
    }
};

И мой скетч Arduino содержит этот код:

#include <MyRadioLibrary.h> 


void setup()  {
    // установка пинов и т.д..
}

void loop()
{

    if (isButton1Pressed())
    {            
        MyRadioLibrary::SendEvent(1, [](bool didEventCompletedSuccessfully) {
            
            if (didEventCompletedSuccessfully)
            {
                // включить зеленый светодиод
            }
            else {

                // включаем красный светодиод
            }

        });
    }
    else if (isButton2Pressed())
    {            
        MyRadioLibrary::SendEvent(2, [](bool didEventCompletedSuccessfully) {
            
             // функция обратного вызова
            
        });
    }

    MyRadioLibrary::loop(); // прослушивание ответных событий. Когда мы получим один пожарный ответный звонок.
}

Теперь вопрос

Когда я вызываю функцию SendEvent, я передаю две вещи (1) целое число и (2) указатель на функцию, которая является обратным вызовом. Целое число (1) передается как значение, и оно будет частью стека функции SendEvent. Указатель (2) будет храниться в массиве указателей. А как насчет лямбда-функции? где она будет храниться? Должен ли я вместо использования лямбда-функции объявить эти функции в глобальной области видимости и передать глобальную функцию вместо лямбда-выражения? Буду ли я рисковать тем, что указатель (2) будет указывать на функцию, которой больше не существует, если я буду использовать этот способ кодирования?

, 👍0

Обсуждение

Насчет «_передать глобальную функцию вместо лямбда_»: после того, как она переведена в машинный код, уже не имеет значения, лямбда это или обычная функция., @Edgar Bonet


1 ответ


Лучший ответ:

2

Ваши функции не перестанут существовать. Весь код в скомпилированном и связанном образе кода загружается в память кода (Flash) и остается там на протяжении всего выполнения, сбросов и циклов включения, пока поверх него не будет загружено другое изображение.

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

,