(伪)C 中的 OOP 从其函数指针获取结构对象
(pseudo) OOP in C get struct object from its function pointer
我正在尝试创建自己的小型 AVR 库。我想在代码中使用伪 OOP,目前我将 "classes" 定义为结构。我正在考虑是否可以实现 "this" 关键字之类的东西。我想在分配给作为结构成员的函数指针的函数中获取结构对象。
我的代码:
#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
宏定义。
那么,我有两个问题。
是否有可能在 avr-gcc 上的分配函数中获取结构对象?如果不是,是否可以在 gcc (windows) 上执行此操作?当然,我可以传递结构对象作为参数,但这会很难看
简短的回答,不 - 要用 container_of
做你想做的事,你需要特定对象中函数指针的地址,而不是它指向的函数的地址,并得到它您需要某种指向结构或传递给函数的成员之一的指针。
如果您看一下 C++ 在幕后所做的事情,它基本上也是将指针传递给结构。你只是看不到它的发生,因为语言对你隐藏了它。必须以某种方式告诉函数您希望它与哪个对象一起工作这一事实是无法解决的——它无法通过魔法知道这一点。
我正在尝试创建自己的小型 AVR 库。我想在代码中使用伪 OOP,目前我将 "classes" 定义为结构。我正在考虑是否可以实现 "this" 关键字之类的东西。我想在分配给作为结构成员的函数指针的函数中获取结构对象。
我的代码:
#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
宏定义。
那么,我有两个问题。 是否有可能在 avr-gcc 上的分配函数中获取结构对象?如果不是,是否可以在 gcc (windows) 上执行此操作?当然,我可以传递结构对象作为参数,但这会很难看
简短的回答,不 - 要用 container_of
做你想做的事,你需要特定对象中函数指针的地址,而不是它指向的函数的地址,并得到它您需要某种指向结构或传递给函数的成员之一的指针。
如果您看一下 C++ 在幕后所做的事情,它基本上也是将指针传递给结构。你只是看不到它的发生,因为语言对你隐藏了它。必须以某种方式告诉函数您希望它与哪个对象一起工作这一事实是无法解决的——它无法通过魔法知道这一点。