2015-09-07 135 views
0

我试图在ARM中创建一个任务队列。基本思想是以下几点。C void *函数指针参数

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编译器会抱怨:

类型的值 “空隙(*)(sADC_Settings *)” 不能被分配给类型 “funcpointer” 的一个实体

关于我如何实现这一点的任何想法?我当然可以改变函数Config_ADC来接受一个void *指针,然后在函数内部对它进行类型转换,但我并不想那么做。

回答

2

IIRC UB通过具有不同签名的函数指针调用函数。

对于每个不匹配的函数类型,您都需要一个代理函数。

void Config_ADC(sADC_Settings *pSettings); 
void Config_ADC_proxy(void *pSettings){ 
    Config_ADC((sADC_Settings*) pSettings); 
} 
+0

有趣的是它似乎与Func_List [0]一起工作。func =(funcpointer)Config_ADC;新的问题是,Config_ADC实际上是一个类的成员函数,当我尝试做Func_List [1] .func =(funcpointer)DrvRX1.Config_ADC;我得到的错误是“一个指向绑定函数的指针只能用来调用函数”,这是所期望的,因为它在调用函数时必须知道这个指针,反正有这个吗? –

+1

@EoinOConnell这是stil未定义的行为。您正在告诉编译器将您必须的函数指针转换为另一种类型,但您仍然会通过不同类型的指针调用。 – RedX

+2

'C'没有成员函数的概念。请用'C++'标签添加一个新问题。我会避免延伸这个问题,因为它涵盖了一个完整的不同主题。此外,这个问题并不是下一个关闭目标,因为之前已经回答了很多次。最好的方法是搜索和找到这样的东西:http://stackoverflow.com/questions/23184662/call-member-function – harper

1

一种解决方案是投在函数中的空指针:

void Config_ADC(void *p) 
{ 
    sADC_Settings *pSettings = (sADC_Settings *)p; 

(其实我不喜欢这个,因为它unnecesarilly占用另一个变量,但是,我认为这已经是好而不是涉及堆栈管理和呼叫管理开销的代理功能,编译器在涉及void *时不应该打扰;那么根本就没有开销。)

+0

你在这里假设,他仍然可以改变Config_ADC功能。如果不是这种情况,他必须使用代理函数来获得免费的UB。 – RedX

0

您的特定ABI规范(s目标处理器,操作系统,甚至是编译器都可以使用)指示如何调用C函数并使用哪个函数calling conventions。注意一些正式的参数可能会通过一些硬件寄存器传递。

我建议使用typedef -s来定义所谓的直通指针功能中的任何签名:

typedef void myroutofint_t(int); 
typedef int myintof2int_t (int, int); 

如果确定被调用函数的签名,如果你可以列出的功能的所有签名呼吁直通的指针,你可以使用一个unamed联盟(C99的C11或):

struct sQueue{ 
enum functiontype_en funtype; 
union { 
    void* funaddress; 
    myroutofint_t *funroutofint; 
    myintof2int_t *funintof2int; 
}; 
// othe fields of SQueue 
}; 

C标准甚至不要求函数指针和指针住在同一个地址空间中的数据,并具有相同的尺寸。但POSIX的确如此,我们假设。

顺便说一句,你可能需要libffi