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

时间:2016-02-16 06:19:30

标签: c++ c function runtime conditional

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)])

我们可以等到运行时来决定是否调用该方法。

有没有办法用"标准" Cc11)或C++std=c14)?

...即

extern void callMeIfYouDare();

int main() { /* if (...) */ callMeIfYouDare(); }

我想我还应该提一下,我正在测试/使用它是在Darwin运行时环境中。

3 个答案:

答案 0 :(得分:2)

在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

如果您将它与定义callMeIfYouDare的库链接,尽管它会调用它。请注意,至少在Mingw32 / Cygwin中需要通过指针。直接调用callMeIfYouDare()将默认导致截断重定位,除非您想要使用链接描述文件是不可避免的。

使用Visual Studio,您可以使用__declspec(selectany)来执行相同的操作:GCC style weak linking in Visual Studio?

更新#1:对于XCode,您可以使用__attribute__((weak_import))代替:Frameworks and Weak Linking

更新#2:对于基于&#34; Apple LLVM 6.0版(clang-600.0.57)的XCode(基于LLVM 3.5svn)&#34;我设法通过使用以下命令进行编译来解决问题:

g++ test_undef.cpp -undefined dynamic_lookup -o test_undef

并保留其他平台的__attribute__((weak))

答案 1 :(得分:1)

C ++或C没有内省。您可以在附加图层中添加一些内容(例如,请查看Qt metaobject或GTK GObject introspection);您可以考虑使用GCC自定义MELT以获得一些内省......(但这需要数周时间)。您可以使用一些额外的脚本或工具来发出与您的内省需求相关的C或C ++代码(SWIG可能是鼓舞人心的)。

在您的特定情况下,您可能希望使用weak symbols(至少在Linux上)。也许使用相关的function attribute代码。

extern void perhapshere(void) __attribute__((weak));
if (perhapshere) 
   perhapshere();

你甚至可以用一些宏来缩短它。

也许您只想加载一些dlopen(3)插件并使用dlsym(3)在其中找到符号(或者甚至在整个程序中使用-rdynamic,通过提供NULL的{​​{1}}路径,并在获取的句柄上使用dlopen;请注意,C ++使用name mangling

所以你可以试试

dlsym

然后:

void*mainhdl = dlopen(NULL, RTLD_NOW);
if (!mainhdl) { fprintf(stderr, "dlopen failed %s\n", dlerror());
                exit(EXIT_FAILURE); };

答案 2 :(得分:1)

如果可以看到在源代码中调用对象(而不是指针)的函数并且代码编译成功 - 则该函数确实存在且不需要检查。

如果通过指针调用函数,则假定您的指针是具有该函数的类的类型。要检查它是否如此,请使用强制转换:

auto* p = dynamic_cast<YourClass*>(somepointer);
if (p != nullptr)
  p->execute();