问题
I have the need to dynamically link against a library at run-time and resolve a series of functions using dlsym
. My first thought was to use an array of function pointers that can be easily iterated through by leveraging a secondary array of char *
representing the symbol names.
However, the problem with this is that not all of the functions take the same arguments. Is there a way to use a generic function pointer in the array, but assign it to a more restrictive function pointer prototype? For example:
If I need to resolve these functions:
int (*functionA)(int)
char (*functionB)(char,int)
Is it possible to do something like (pseudo-ish .. )
void* functionList(...)[2] = {functionA, functionB};
Along with
char FuncNameA[] = "functionA";
char FuncNameB[] = "functionB";
char *functionNames[2] = {FuncNameA, FuncNameB};
For the purpose of looping though the call to dlsym
for symbol resolution
int i = 0;
for(; i<2; i++)
functionList[i] = dlsym(DL_OPEN_HANDLE, functionNames[i]);
Where DL_OPEN_HANDLE would be defined by an earlier call to dlopen
.
回答1:
The C standard guarantees that any object pointer type can be converted to void*
and back again without loss of information (meaning that the re-converted pointer will compare equal to the original one).
There is no such guarantee for function pointers. An implementation could, for example, make void*
64 bits and function pointers 128 bits.
But any function pointer can be converted to any other function pointer type and back again without loss of information.
You can use, for example, void(*)(void)
as a generic function pointer type:
typedef void (*funcptr)(void);
You must convert back to the original pointer type before executing a call to avoid undefined behavior.
On the other hand, you're using dlsym()
, which returns a void*
. My understanding is that POSIX guarantees that the void*
returned by dlsym()
(if the name
argument names a function) can be converted to a function pointer, which can be used to call the function. If the only functions you care about are those whose addresses are returned by dlsym()
, then you can use void*
.
(POSIX previously guaranteed, as an extension to the C standard, that a function pointer can be converted to void*
and back again. That guarantee was later dropped. Thanks to Jonathan Leffler for pointing this out.)
In any case, using function pointers to store the addresses of functions probably makes for clearer code.
回答2:
You should probably define your list as void *functionList[2]
, since dlsym
returns a void *
. Once you know which function you have, you can cast it to the proper type.
void *functionList[2];
...
int (*functionA)(int) = (int(*)(int))functionList[0];
char (*functionB)(char,int) = (char(*)(char, int))functionList[1];
回答3:
dlsym
returns a data pointer of type void *
, but POSIX guarantees that this can be cast to a function pointer of the appropriate type:
Implementations supporting the XSI extension [...] require that an object of type
void *
can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (exceptvoid *
) is still undefined, however.
Since Version 7 of POSIX, all implementations (not just XSI) are required to support the conversion.
Because conversion from a void *
pointer to a function pointer via a direct cast can result in compiler warnings, older versions of POSIX recommend performing the conversion via aliasing:
int (*fptr)(int);
*(void **)(&fptr) = dlsym(handle, "my_function");
In the current version the recommendation is changed to:
int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");
来源:https://stackoverflow.com/questions/31482624/is-there-such-a-thing-as-a-generic-function-pointer-in-c-that-can-be-assigned-ca