是否可以确定(在运行时)功能是否已实现?

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)) 其他平台的原样。