Obj-C有@available。Swift有#available。在C / C ++中可以使用什么?

Mec*_*cki 2 c macos objective-c swift

如果您的代码需要仅在macOS 10.12或更高版本中可用的功能,但又希望代码也可以部署到较早的系统版本,则可以@available在Objective-C中使用:

if (@available(macOS 10.12, *)) {
    // Code that requires 10.12 APIs
} else {
    // Code that doesn't require 10.12 APIs
}
Run Code Online (Sandbox Code Playgroud)

您可以在Swift中使用#available以下命令执行相同的操作:

if #available(OSX 10.12, *) {
    // Code that requires 10.12 APIs
} else {
    // Code that doesn't require 10.12 APIs
}
Run Code Online (Sandbox Code Playgroud)

但是,如果编写C或C ++代码,可以使用什么呢?

Mec*_*cki 5

在C和C ++中,您可以使用Clang编译器扩展__builtin_available

if (__builtin_available(OSX 10.12, *)) {
    // Code that requires 10.12 APIs
} else {
    // Code that doesn't require 10.12 APIs
}
Run Code Online (Sandbox Code Playgroud)

也就是说,如果您至少有Clang 5可用(Xcode 5.0或更高版本)。

请记住,您必须设置一个部署目标才能使此功能正常工作(例如-mmacosx-version-min=10.9)。原因是链接器需要此信息来决定何时执行弱链接。例如,将部署目标设置为10.9会告诉链接器,如果您的代码使用的是10.9中尚不可用的任何符号,则这些符号必须进行弱链接。

通常,可执行文件或库将尝试在加载时解析所有引用的符号,如果找不到任何此类符号,则加载失败。但是,当符号链接较弱时,无法解析符号不会导致加载失败,而是对该符号的任何引用都会NULL在运行时变为引用。不用说,如果您尝试调用一个链接较弱且未在加载时找到的函数,则您的应用程序将崩溃。这就是__builtin_available救援的地方。

if (__builtin_available(OSX 10.12, *)) {
    // ...
} else {
    // Symbols only available in 10.12 or newer are all NULL when
    // you reach this code block but you wouldn't use any of them
    // in this code block, would you? So, no problem.
}
Run Code Online (Sandbox Code Playgroud)

如果您不使用-mmacosx-version-min,该__builtin_available构造将仍然可以正常工作,但是由于链接器不知道您要定位的系统,因此它将假定当前系统并且不会执行任何弱链接。如果您随后尝试在较早的系统版本上运行您的应用程序,尽管该应用程序具有该版本的替代代码路径,但找不到某些符号,甚至拒绝加载您的应用程序。