如果我们导入了 Darwin 的 C 库的话,我们就可以在 Swift 中无缝地使用 Darwin 中定义的 C 函数了。它们涵盖了绝大多数 C 标准库中的内容,可以说为程序设计提供了丰富的工具和基础。导入 Darwin 十分简单,只需要加上 import Darwin 即可。但事实上,Foundation 框架中包含了 Darwin 的导入,而我们在开发 app 时肯定会使用 UIKit 或者 Cocoa 这样的框架,它们又导入了 Foundation,因此我们在平时开发时并不需要特别做什么,就可以使用这些标准的 C 函数了。很让人开心的一件事情是 Swift 在导入时为我们将 Darwin 也进行了类型的自动转换对应,比如对于三角函数的计算输入和返回都是 Swift 的 Double 类型,而非 C 的类型:

func sin(x: Double) -> Double

使用起来也很简单,因为这些函数都是定义在全局的,所以只需要直接调用就可以了:

sin(M_PI_2)
// 输出:1.0

而对于第三方的 C 代码,Swift 也提供了协同使用的方法。我们知道,Swift 中调用 Objective-C 代码非常简单,只需要将合适的头文件暴露在 {product-module-name}-Bridging-Header.h 文件中就行了。而如果我们想要调用非标准库的 C 代码的话,可以遵循同样的方式,将 C 代码的头文件在桥接的头文件中进行导入:

//test.h
int test(int a);

//test.c
int test(int a) {
    return a + 1;
}

//Module-Bridging-Header.h
#import "test.h"

//File.swift
func testSwift(input: Int32) {
    let result = test(input)
    print(result)
}

testSwift(1)
// 输出:2

另外,我们甚至还有一种不需要借助头文件和 Bridging-Header 来导入 C 函数的方法,那就是使用 Swift 中的一个隐藏的符号 @asmname@asmname 可以通过方法名字将某个 C 函数直接映射为 Swift 中的函数。比如上面的例子,我们可以将 test.hModule-Bridging-Header.h 都删掉,然后将 swift 文件中改为下面这样,也是可以正常进行使用的:

//File.swift
//将 C 的 test 方法映射为 Swift 的 c_test 方法
@asmname("test") func c_test(a: Int32) -> Int32

func testSwift(input: Int32) {
    let result = c_test(input)
    print(result)
}

testSwift(1)
// 输出:2

这种导入在第三方 C 方法与系统库重名导致调用发生命名冲突时,可以用来为其中之一的函数重新命名以解决问题。当然我们也可以利用 Module 名字 + 方法名字的方式来解决这个问题。

除了作为非头文件方式的导入之外,@asmname 还承担着和 @objc 的 “重命名 Swift 中类和方法名字” 类似的任务,这可以将 C 中不认可的 Swift 程序元素字符重命名为 ascii 码,以便在 C 中使用。