我正在尝试在ARM中创建任务队列。基本思路如下。
typedef void (*funcpointer)(void *); // the argument being passed will be a void pointer that I can hopefully typecast
struct sQueue{
funcpointer func_address; // this stores the address of the function to be called
void *func_parameter; // this stores the address of the struct that is passed to the function
uint32_t TimeStamp; // the time at which the function should be called
};
sQueue Func_List[10];
计划是能够在Func_List [x] .func_address中放置应该调用的函数的地址。
我希望能够将接受指针的函数的地址放在func_address中的不同结构类型中。 这是一个例子:
void Config_ADC(sADC_Settings *pSettings);
void Enable_RX(sRX_Top_Settings *pSettings);
两个函数都有效地接受一个结构的32位指针,但在这些情况下,结构是不同类型的。
当我尝试分配Func_List [x] .func_address = Config_ADC时,编译器会抱怨:
类型为“void(*)(sADC_Settings *)”的值无法分配给“funcpointer”类型的实体
关于如何实现这一目标的任何想法?我当然可以更改函数Config_ADC以接受void *指针,然后在函数内部进行类型转换,但我真的不想这样做。
答案 0 :(得分:2)
IIRC通过具有不同签名的函数指针调用函数是UB。
每个不匹配的函数类型都需要一个代理函数。
void Config_ADC(sADC_Settings *pSettings);
void Config_ADC_proxy(void *pSettings){
Config_ADC((sADC_Settings*) pSettings);
}
答案 1 :(得分:1)
解决方案是将void指针强制转换为函数:
void Config_ADC(void *p)
{
sADC_Settings *pSettings = (sADC_Settings *)p;
(实际上我不喜欢这个,因为它不太可能占用另一个变量,但是,我认为它已经比涉及堆栈管理和调用管理开销的代理函数更好。编译器不应该在{{1}时打扰参与其中;然后就没有任何开销。)
答案 2 :(得分:0)
您的特定ABI规范(特定于目标处理器,操作系统,甚至编译器)规定了如何调用C函数以及calling conventions。请注意,某些正式参数可能会通过某些硬件寄存器传递。
我建议使用typedef
- s来定义通过指针调用的任何函数签名:
typedef void myroutofint_t(int);
typedef int myintof2int_t (int, int);
如果您确定被调用函数的签名,并且如果您可以列出通过指针调用的函数的所有签名,则可以使用未命名的并集(在C99或C11中):
struct sQueue{
enum functiontype_en funtype;
union {
void* funaddress;
myroutofint_t *funroutofint;
myintof2int_t *funintof2int;
};
// othe fields of SQueue
};
C标准甚至不要求函数指针和数据指针存在于同一地址空间并且具有相同的大小。但POSIX确实如此,我们认为。
顺便说一句,您可能需要libffi。