是否可以确定(在运行时)功能是否已实现?
Is it possible to determine (at runtime) if a function has been implemented?
Objective C
的主要特点之一是简单 introspection。此功能的典型用途是能够在调用之前检查某些方法(函数)以确保它确实存在。
而下面的代码 将 在运行时抛出错误(尽管它 编译 很好 (Apple LLVM version 7.0.2 (clang-700.1.81)
))。 ..
@import Foundation;
@interface Maybe : NSObject + (void) maybeNot; @end
@implementation Maybe @end
int main (){ [Maybe maybeNot]; }
通过在调用前添加一个简单的条件...
if ([Maybe respondsToSelector:@selector(maybeNot)])
我们可以等到运行时再决定是否调用该方法。
有没有办法用 "standard" C
(c11
) 或 C++
(std=c14
) 做到这一点?
即....
extern void callMeIfYouDare();
int main() { /* if (...) */ callMeIfYouDare(); }
我想我还应该提到我是 testing/using 这是在 Darwin
运行时环境中。
C++ 或 C 没有内省。您可以在附加层中添加一些(看看 Qt metaobject, or GTK GObject introspection for examples); you might consider customizing GCC with MELT to get some introspection... (but that would take weeks). You could have some additional script or tool which emits C or C++ code related to your introspection needs (SWIG 可能会鼓舞人心)。
在您的特定情况下,您可能希望使用 weak symbols (at least on Linux). Perhaps use the relevant function attribute so 代码。
extern void perhapshere(void) __attribute__((weak));
if (perhapshere)
perhapshere();
你甚至可以用一些宏来缩短它。
也许您只是想用 dlopen(3) and use dlsym(3) to find symbols in it (or even in the whole program which you would link with -rdynamic
, by giving the NULL
path to dlopen
and using dlsym
on the obtained handle); be aware that C++ uses name mangling 加载一些插件。
所以你可以试试
void*mainhdl = dlopen(NULL, RTLD_NOW);
if (!mainhdl) { fprintf(stderr, "dlopen failed %s\n", dlerror());
exit(EXIT_FAILURE); };
然后稍后:
typedef void voidvoidsig_t (void); // the signature of perhapshere
void* ad = dlsym(mainhdl, "perhapshere");
if (ad != NULL) {
voidvoidsig_t* funptr = (voidvoidsig_t*)ad;
(*funptr)();
}
如果您可以看到在源代码中调用了一个对象(不是指针)的函数并且代码编译成功 - 那么该函数确实存在并且不需要检查。
如果通过指针调用一个函数,那么您假设您的指针属于具有该函数的 class 类型。要检查它是否如此,您可以使用转换:
auto* p = dynamic_cast<YourClass*>(somepointer);
if (p != nullptr)
p->execute();
在 GNU gcc / Mingw32 / Cygwin 上你可以使用 Weak symbol:
#include <stdio.h>
extern void __attribute__((weak)) callMeIfYouDare();
void (*callMePtr)() = &callMeIfYouDare;
int main() {
if (callMePtr) {
printf("Calling...\n");
callMePtr();
} else {
printf("callMeIfYouDare() unresolved\n");
}
}
编译并运行:
$ g++ test_undef.cpp -o test_undef.exe
$ ./test_undef.exe
callMeIfYouDare() unresolved
如果您 link 使用定义了 callMeIfYouDare 的库,尽管它会调用它。请注意,至少在 Mingw32/Cygwin 中必须通过指针。直接调用 callMeIfYouDare() 将导致默认情况下的 t运行 重定位,除非您想使用 linker 脚本,否则这是不可避免的。
使用 Visual Studio,您也许可以让 __declspec(selectany) 执行相同的操作:GCC style weak linking in Visual Studio?
更新 #1:对于 XCode,您可以根据以下条件使用 __attribute__((weak_import))
:Frameworks and Weak Linking
更新 #2:对于基于 "Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)" 的 XCode 我设法通过使用以下命令进行编译来解决问题:
g++ test_undef.cpp -undefined dynamic_lookup -o test_undef
并保留 __attribute__((weak))
其他平台的原样。
Objective C
的主要特点之一是简单 introspection。此功能的典型用途是能够在调用之前检查某些方法(函数)以确保它确实存在。
而下面的代码 将 在运行时抛出错误(尽管它 编译 很好 (Apple LLVM version 7.0.2 (clang-700.1.81)
))。 ..
@import Foundation;
@interface Maybe : NSObject + (void) maybeNot; @end
@implementation Maybe @end
int main (){ [Maybe maybeNot]; }
通过在调用前添加一个简单的条件...
if ([Maybe respondsToSelector:@selector(maybeNot)])
我们可以等到运行时再决定是否调用该方法。
有没有办法用 "standard" C
(c11
) 或 C++
(std=c14
) 做到这一点?
即....
extern void callMeIfYouDare();
int main() { /* if (...) */ callMeIfYouDare(); }
我想我还应该提到我是 testing/using 这是在 Darwin
运行时环境中。
C++ 或 C 没有内省。您可以在附加层中添加一些(看看 Qt metaobject, or GTK GObject introspection for examples); you might consider customizing GCC with MELT to get some introspection... (but that would take weeks). You could have some additional script or tool which emits C or C++ code related to your introspection needs (SWIG 可能会鼓舞人心)。
在您的特定情况下,您可能希望使用 weak symbols (at least on Linux). Perhaps use the relevant function attribute so 代码。
extern void perhapshere(void) __attribute__((weak));
if (perhapshere)
perhapshere();
你甚至可以用一些宏来缩短它。
也许您只是想用 dlopen(3) and use dlsym(3) to find symbols in it (or even in the whole program which you would link with -rdynamic
, by giving the NULL
path to dlopen
and using dlsym
on the obtained handle); be aware that C++ uses name mangling 加载一些插件。
所以你可以试试
void*mainhdl = dlopen(NULL, RTLD_NOW);
if (!mainhdl) { fprintf(stderr, "dlopen failed %s\n", dlerror());
exit(EXIT_FAILURE); };
然后稍后:
typedef void voidvoidsig_t (void); // the signature of perhapshere
void* ad = dlsym(mainhdl, "perhapshere");
if (ad != NULL) {
voidvoidsig_t* funptr = (voidvoidsig_t*)ad;
(*funptr)();
}
如果您可以看到在源代码中调用了一个对象(不是指针)的函数并且代码编译成功 - 那么该函数确实存在并且不需要检查。
如果通过指针调用一个函数,那么您假设您的指针属于具有该函数的 class 类型。要检查它是否如此,您可以使用转换:
auto* p = dynamic_cast<YourClass*>(somepointer);
if (p != nullptr)
p->execute();
在 GNU gcc / Mingw32 / Cygwin 上你可以使用 Weak symbol:
#include <stdio.h>
extern void __attribute__((weak)) callMeIfYouDare();
void (*callMePtr)() = &callMeIfYouDare;
int main() {
if (callMePtr) {
printf("Calling...\n");
callMePtr();
} else {
printf("callMeIfYouDare() unresolved\n");
}
}
编译并运行:
$ g++ test_undef.cpp -o test_undef.exe
$ ./test_undef.exe
callMeIfYouDare() unresolved
如果您 link 使用定义了 callMeIfYouDare 的库,尽管它会调用它。请注意,至少在 Mingw32/Cygwin 中必须通过指针。直接调用 callMeIfYouDare() 将导致默认情况下的 t运行 重定位,除非您想使用 linker 脚本,否则这是不可避免的。
使用 Visual Studio,您也许可以让 __declspec(selectany) 执行相同的操作:GCC style weak linking in Visual Studio?
更新 #1:对于 XCode,您可以根据以下条件使用 __attribute__((weak_import))
:Frameworks and Weak Linking
更新 #2:对于基于 "Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)" 的 XCode 我设法通过使用以下命令进行编译来解决问题:
g++ test_undef.cpp -undefined dynamic_lookup -o test_undef
并保留 __attribute__((weak))
其他平台的原样。