Процедура обслуживания прерывания в C++

Для встроенной системы реального времени я пытаюсь предоставить обработчик прерывания, который позволяет регистрировать любой указатель нестатического метода (а также экземпляр объекта, конечно), который вызывается, когда происходит прерывание.

В C это было легко сделать, например:

void (*func)(void*) = 0; // <- method to be called goes here
void* instance;          // <- instance for this-call goes here

void InterruptHandler()
{
  func(instance);
}

Afaik, это соответствует вызову this, который С++ делает неявно при вызове нестатического метода.

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

Есть ли способ напрямую эмулировать этот вызов С++, как в C? Я знаю о делегатах, однако мой компилятор ограничен С++ 98, без библиотеки повышения и т. д.; и даже настраиваемые облегченные реализации, например. Невероятно быстрые делегаты C++ Сергея Рязанова обеспечивают определенные накладные расходы, которых я хотел бы избежать, если это возможно.


person SirFrancisDrake    schedule 19.07.2016    source источник
comment
Методы всегда имеют скрытый параметр this, который, вероятно, сбивает вас с толку. Много полезной информации и советов здесь: isocpp.org/wiki/faq/pointers-to -члены   -  person user4581301    schedule 19.07.2016


Ответы (1)


Методы всегда содержат скрытый параметр this для предоставления доступа к вызываемому объекту. Чтобы вызвать класс из обработчика прерываний, который ожидает C или C-подобное поведение вызова с соответствием 1:1 между перечисленными параметрами и необходимыми параметрами, вы должны обеспечить это C-подобное поведение. Это означает бесплатные функции или статические методы без скрытых параметров.

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

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

Данный

void (*func)(void*)

Там, где void * является указателем на предоставленную пользователем управляющую информацию, простым решением является статический метод или свободная функция вида

void handlerCaller(void* userp)
{
    ISRHandlerClass * handlerp = (ISRHandlerClass *) userp;
    handlerp->isrhandler(); // tiny bit may be lost here to subclass look-up
}

А также

void isrhandler()

реализован, чтобы делать все, что, черт возьми, нужно делать ISRHandlerClass или дочернему элементу ISRHandlerClass.

Вы в значительной степени застряли с handlerCaller или чем-то очень похожим, так что вы не можете избежать накладных расходов. Остальное зависит от того, насколько общим должен быть интерфейс ISR.

Простой универсальный базовый класс обработчика ISR:

class ISRHandlerClass
{
    public:
        virtual ~ISRHandlerClass()
        {
        }
        // pure virtual to be implemented by specialized handler
        virtual void isrhandler() = 0;  
};

и такой же простой реализатор

class FooHandler: public ISRHandlerClass
{
    public:
        void isrhandler() //override tag if you've got 'em
        {
            // read Foo and store in buffer to be processed by lower priority task
        }  
};

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

void FooHandlerCaller(void* userp)
{
    FooHandler * handlerp = (FooHandler *) userp;
    handlerp->isrhandler();
}

void BarHandlerCaller(void* userp)
{
    BarHandler * handlerp = (BarHandler *) userp;
    handlerp->isrhandler();
}

Or

template <class TYPE>
void handlerCaller(void* userp)
{
    TYPE * handlerp = (TYPE *) userp;
    handlerp->isrhandler();
}

Применение

class FooHandler
{
    public:
        void isrhandler()
        {
            // read Foo and store in buffer to be processed by lower priority task
        }  
};

void (*func)(void*) = handlerCaller<FooHandler>;
FooHandler handler;
void* instance = (void *)&handler;
person user4581301    schedule 19.07.2016