2016-02-13 11 views
1

Я пытаюсь создать свою собственную небольшую библиотеку AVR. У меня есть идея использовать псевдо ООП в коде, и в настоящее время у меня есть «классы», определенные как структуры. Я рассматриваю, возможно ли реализовать что-то вроде этого «ключевого слова». Я хочу, чтобы объект struct внутри функции был назначен указателю на функцию, который является членом struct.(pseudo) OOP в C Получить объект struct из его указателя функции

Мой код:

#define __class__     struct 
#define __inner_object__   struct 

#define ALIAS(cls, stc)    typedef __class__ cls stc 
typedef uint8_t  reg8_t; 

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 
#define container_of(ptr, type, member) ({      \ 
    const typeof(((type *)0)->member) *__mptr = (ptr); \ 
    (type *)((char *)__mptr - offsetof(type,member));}) 

typedef enum { 
    PIN_DIR_INPUT = 0, 
    PIN_DIR_OUTPUT = 1 
} pin_direction_t; 

typedef struct { 
    const reg8_t  m_pin; 
    const reg8_t  m_ddr; 
    const reg8_t  m_port; 
    const u1   m_bit; 

    void    (*setDirection)(pin_direction_t); 
} pin_t; 

void __setDirection(pin_direction_t direction) 
{ 
    // how to get struct object here? 
    pin_t* pin = container_of(__setDirection, pin_t, setDirection); 
    //uint8_t reg = reg_read(pin->m_ddr); 
    //if (direction == PIN_DIR_OUTPUT) 
     //reg_write(pin->m_ddr, reg | (1uL << pin->m_bit)); 
    //else 
     //reg_write(pin->m_ddr, reg & ~(1uL << pin->m_bit)); 
} 

__class__ at_mega8 
{ 
    __inner_object__ 
    { 
     const reg8_t REG_PIND; 
     const reg8_t REG_DDRD; 
     const reg8_t REG_PORTD; 
     __inner_object__ 
     { 
      const pin_t PIN_D7; 
      const pin_t PIN_D6; 
      const pin_t PIN_D5; 
      const pin_t PIN_D4; 
      const pin_t PIN_D3; 
      const pin_t PIN_D2; 
      const pin_t PIN_D1; 
      const pin_t PIN_D0; 
     } Pins; 
    } PortD; 

    __inner_object__ 
    { 
     const reg8_t REG_PINC; 
     const reg8_t REG_DDRC; 
     const reg8_t REG_PORTC; 
     __inner_object__ 
     { 
      const pin_t PIN_C6; 
      const pin_t PIN_C5; 
      const pin_t PIN_C4; 
      const pin_t PIN_C3; 
      const pin_t PIN_C2; 
      const pin_t PIN_C1; 
      const pin_t PIN_C0; 
     } Pins; 
    } PortC; 

    __inner_object__ 
    { 
     const reg8_t REG_PINB; 
     const reg8_t REG_DDRB; 
     const reg8_t REG_PORTB; 
     __inner_object__ 
     { 
      const pin_t PIN_B7; 
      const pin_t PIN_B6; 
      const pin_t PIN_B5; 
      const pin_t PIN_B4; 
      const pin_t PIN_B3; 
      const pin_t PIN_B2; 
      const pin_t PIN_B1; 
      const pin_t PIN_B0; 
     } Pins; 
    } PortB; 
}; 

ALIAS(at_mega8, at_mega8_t); 

#define M8_PIND  0x10 
#define M8_DDRD  0x11 
#define M8_PORTD 0x12 

#define M8_PINC  0x13 
#define M8_DDRC  0x14 
#define M8_PORTC 0x15 

#define M8_PINB  0x16 
#define M8_DDRB  0x17 
#define M8_PORTB 0x18 

const at_mega8_t AtMega8 = { 
    { 
     M8_PIND, M8_DDRD, M8_PORTD, 
     { 
      { .m_bit = 7, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 6, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 5, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 4, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 3, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 2, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 1, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
      { .m_bit = 0, .m_pin = M8_PIND, .m_ddr = M8_DDRD, .m_port = M8_PORTD, .setDirection = __setDirection }, 
     } 
    }, 
    { 
     M8_PINC, M8_DDRC, M8_PORTC, 
     { 
      { .m_bit = 6, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 5, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 4, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 3, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 2, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 1, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
      { .m_bit = 0, .m_pin = M8_PINC, .m_ddr = M8_DDRC, .m_port = M8_PORTC, .setDirection = __setDirection }, 
     } 
    }, 
    { 
     M8_PINB, M8_DDRB, M8_PORTB, 
     { 
      { .m_bit = 7, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 6, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 5, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 4, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 3, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 2, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 1, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
      { .m_bit = 0, .m_pin = M8_PINB, .m_ddr = M8_DDRB, .m_port = M8_PORTB, .setDirection = __setDirection }, 
     } 
    }, 
}; 

Я мог бы использовать этот код в примере ниже:

hd44780.pinout.pinRS = &AtMega8.PortB.Pins.PIN_B1; 
hd44780.init(); 
// and somewhere else in hd44780: 
// rsPin.setDirection(PIN_DIR_OUTPUT); 

Я знаю, что есть container_of макрос, который позволяет получить объект контейнера его членом. Но когда я пытаюсь использовать этот макрос я получаю сообщение об ошибке:

error: dereferencing pointer to incomplete type

Эта ошибка указывает на container_of макроопределения.

Итак, у меня есть два вопроса. Возможно ли получить объект struct внутри назначенной функции на avr-gcc? Если нет, можно ли это сделать на gcc (windows)? Конечно, я мог бы передать объект struct, чтобы функционировать как paramater, но это было бы уродливо.

ответ

1

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

Если вы посмотрите, что, скажем, C++, делает под капотом, он также в основном передает указатель на структуру. Вы просто не видите, что это происходит, потому что язык скрывает его от вас. Нет никакого способа обойти тот факт, что каким-то образом функция должна быть проинформирована о том, с каким объектом вы хотите работать, - она ​​не может знать это по магии.

+0

Благодарим за ответ. Я думаю, что я могу остаться в пути, чтобы передать указатель объекта структуры для функции в качестве параметра. Я попытаюсь реализовать кучу, и, возможно, я каким-то образом получаю объект struct из функции. Спасибо за совет. – shjeff