我的问题如下:
我有一个包含函数指针的结构,如下所示:
typedef void (CALLING_COVNENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
}myFuncpointerStruc_t;
现在我想为其分配一个完全相同类型的函数指针。
但遗憾的是 dlsym()
返回的是 void *
而不是 function_poitner_type
所以我的第一次尝试:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
structIdentifier.funcIdentifier= dlsym (hAndle, "calledName");
}
以警告结束:
WARNING: ISO C forbids assignment between function pointer and 'void *'
好吧,这让我很困惑……海湾合作委员会从来没有对我说过那么严厉的话。 但好吧,让我们变得棘手,我认为可能会有任何后门来保持其标准一致。所以我尝试了这个:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
*(void **) &structIdentifier.funcIdentifier = dlsym (hAndle, "calledName");
}
嗯......显然......
warning: dereferencing type-punned pointer will break strict aliasing rules
因为我不知道dlsym()
内部发生了什么,所以我不知道我会中断,因为我返回了一个真正的void *
,它为我的函数起别名,或者完全不同的东西,可以吗?
所以我不知道,现在使用这个函数指针是否会违反严格别名规则?
但无论如何:对于我的公司来说,使用编译器标志 -fstrict-aliasing
是合法的。
所以这对我来说也不是一个可能的解决方案,即使它是符合要求的。
所以我继续尝试。
我的下一个想法是:如何将 dlsym()
的 char *
版本解析为 memcopy?
结果:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
memcpy (g_interfaceSvCheck.pfnPFD_SVCHK_GET_VERSION, localTestPtr, sizeof (localTestPtr));
}
我现在收到的警告再次非常具体:
warning: ISO C forbids passing argument 1 of ´memcpy´ between function pointer and ´void *´
所以我的下一个想法是“让我们回到字节”也许我会找到一种可行的方法。 (但慢慢地我就没有想法了......)
所以我做到了:
functionscope ()
{
size_t testIndex;
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
{
((unsigned char *)(structIdentifier.funcIdentifier))[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
}
}
这以一个安静的不同警告结束:
WARNING: ISO C forbids conversion of function pointer to object pointer type
所以最后我最奇怪的尝试是:
functionscope ()
{
size_t testIndex;
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
unsigned char * FakeFunctionPointer;
FakeFunctionPointer =
(((unsigned char *)structIdentifier) + offsetof (myFuncpointerStruc_t , funcIdentifier));
for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
{
FakeFunctionPointer[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
}
}
即使在这里,问题是,offsetoff
的第二个参数无法转换为 void *
,因为它是一个函数指针。
我陷入困境,不知道如何进一步发展,有人可以帮我找到解决方案吗?
我只是使用 gcc 4.2 而不是 clang 收到这些警告。
objective-c 版本是 -std=c99
,要避免的是 -std=POSIX
和 -std=gnu99
但是这个 gcc 警告对我来说听起来并没有过时。 我目前正在 FreeBSD 上工作,我真的不知道如何解决这个问题。
最佳答案
这有点棘手:
#define CALLING_CONVENTION
typedef void (CALLING_CONVENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
} myFuncpointerStruc_t;
int main()
{
myFuncpointerStruc_t structIdentifier = {0};
{
functionType_t * pfuncIdentifier = &structIdentifier.funcIdentifier;
*(void **) (pfuncIdentifier) = dlsym(handle, "calledName");
}
...
}
上面的解决方案只是欺骗编译器。 不再在-O1
上工作......:-(
确实没有办法解决,唯一的办法就是让编译器冷静下来。 GNU 人们对此表现出了洞察力并发明了:__attribute__ ((__may_alias__))
这里我们可以按如下方式使用它:
#define CALLING_CONVENTION
typedef void * __attribute__ ((__may_alias__)) pvoid_may_alias_t;
typedef void (CALLING_CONVENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
} myFuncpointerStruc_t;
int main()
{
myFuncpointerStruc_t structIdentifier = {0};
*(pvoid_may_alias_t *) (&structIdentifier.funcIdentifier) = dlsym(handle, "calledName");
}
...
}
顺便说一句:ldsym()
从哪里来?我只知道dlsym()
。
关于c - 如何将 dlsym() 的返回值分配给函数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19116487/