C语言 如何从 Swift 调用 C?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24004732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call C from Swift?
提问by Blaze
Is there a way to call C routines from Swift?
有没有办法从 Swift 调用 C 例程?
A lot of iOS / Apple libraries are C only and I'd still like to be able to call those.
许多 iOS / Apple 库都是 C 语言,我仍然希望能够调用它们。
For example, I'd like to be able to call the objc runtime libraries from swift.
例如,我希望能够从 swift 调用 objc 运行时库。
In particular, how do you bridge iOS C headers?
特别是,你如何桥接 iOS C 头文件?
采纳答案by Leandros
Yes, you can of course interact with Apples C libraries. Hereis explained how.
Basically, the C types, C pointers, etc are translated into Swift objects, for example a C intin Swift is a CInt.
是的,您当然可以与 Apples C 库进行交互。这里解释了如何。
基本上,C 类型、C 指针等被转换为 Swift 对象,例如intSwift 中的 C是CInt.
I've build a tiny example, for another question, which can be used as a little explanation, on how to bridge between C and Swift:
我为另一个问题构建了一个小例子,它可以作为一个小小的解释,关于如何在 C 和 Swift 之间架起桥梁:
main.swift
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
UserInput.c
用户输入文件
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
cliinput-Bridging-Header.h
void getInput(int *output);
Hereis the original answer.
这是原始答案。
回答by rickster
The compiler converts C API to Swift just like it does for Objective-C.
编译器将 C API 转换为 Swift,就像它为 Objective-C 所做的那样。
import Cocoa
let frame = CGRect(x: 10, y: 10, width: 100, height: 100)
import Darwin
for _ in 1..10 {
println(rand() % 100)
}
See Interacting with Objective-C APIsin the docs.
请参阅文档中的与 Objective-C API 交互。
回答by lukas83
Just in case you're as new to XCode as me and want to try the snippets posted in Leandro's answer:
以防万一您和我一样对 XCode 不熟悉,并且想尝试Leandro 的回答中发布的片段:
- File->New->Project
- choose Command Line Tool as a project preset and name the project "cliinput"
- right-click in the project navigator (the blue panel on the left) and choose "New File..."
- In the drop down dialog name the file "UserInput". Uncheck the box "Also create a header file". Once you click "Next" you will be asked if XCode should create the Bridging-Header.h file for you. Choose "Yes".
- Copy & paste the code from Leandro's answer above. Once you click on the play button it should compile and run in the terminal, which in xcode is built-in in the bottom panel. If you enter a number in the terminal, a number will be returned.
- 文件->新建->项目
- 选择命令行工具作为项目预设并将项目命名为“cliinput”
- 右键单击项目导航器(左侧的蓝色面板)并选择“新建文件...”
- 在下拉对话框中命名文件“UserInput”。取消选中“同时创建头文件”框。单击“下一步”后,系统会询问 XCode 是否应为您创建 Bridging-Header.h 文件。选择“是”。
- 复制并粘贴上面 Leandro 回答中的代码。单击播放按钮后,它应该会在终端中编译并运行,在 xcode 中,它内置在底部面板中。如果您在终端中输入一个数字,则会返回一个数字。
回答by Julian
This postalso has a good explanation regarding how to do this using clang's module support.
这篇文章也很好地解释了如何使用 clang 的模块支持来做到这一点。
It's framed in terms of how to do this for the CommonCrypto project, but in general it should work for any other C library you want to use from within Swift.
它是根据如何为 CommonCrypto 项目执行此操作而设计的,但总的来说,它应该适用于您想在 Swift 中使用的任何其他 C 库。
I briefly experimented with doing this for zlib. I created a new iOS framework project and created a directory zlib, containing a module.modulemap file with the following:
我简要地尝试为 zlib 执行此操作。我创建了一个新的 iOS 框架项目并创建了一个目录 zlib,其中包含一个具有以下内容的 module.modulemap 文件:
module zlib [system] [extern_c] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
export *
}
Then under Targets -> Link Binary With Libraries I selected add items and added libz.tbd.
然后在 Targets -> Link Binary With Libraries 下,我选择了添加项目并添加了 libz.tbd。
You may want to build at this point.
此时您可能想要构建。
I was then able to write the following code:
然后我能够编写以下代码:
import zlib
public class Zlib {
public class func zlibCompileFlags() -> UInt {
return zlib.zlibCompileFlags()
}
}
You don't haveto put the zlib library name in front, except in the above case I named the Swift class func the same as the C function, and without the qualification the Swift func ends up being called repeatedly until the application halts.
你不具备把zlib库的名字在前面,除了在命名雨燕类FUNC一样的C函数上述情况下,我,没有资格雨燕FUNC最终被重复调用,直到应用程序暂停。
回答by John James
In the case of c++, there is this error that pops up:
在c++的情况下,会弹出这个错误:
"_getInput", referenced from:
You need a c++ header file too. Add c-linkageto your function, then include the header file in the bridge-header:
您也需要一个 C++ 头文件。将c-linkage添加到您的函数中,然后在桥头文件中包含头文件:
Swift 3
斯威夫特 3
UserInput.h
用户输入.h
#ifndef USERINPUT_H
#define USERINPUT_H
#ifdef __cplusplus
extern "C"{
#endif
getInput(int *output);
#ifdef __cplusplus
}
#endif
UserInput.c
用户输入文件
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
main.swift
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
print(output)
cliinput-Bridging-Header.h
cliinput-Bridging-Header.h
#include "UserInput.h"
Here is the original video explaining this
回答by Chris Prince
It appears to be a rather different ball 'o wax when dealing with pointers. Here's what I have so far for calling the C POSIX readsystem call:
在处理指针时,它似乎是一个相当不同的蜡球。到目前为止,这是我调用 C POSIXread系统调用的方法:
enum FileReadableStreamError : Error {
case failedOnRead
}
// Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer
// and https://gist.github.com/kirsteins/6d6e96380db677169831
override func readBytes(size:UInt32) throws -> [UInt8]? {
guard let unsafeMutableRawPointer = malloc(Int(size)) else {
return nil
}
let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size))
if numberBytesRead < 0 {
free(unsafeMutableRawPointer)
throw FileReadableStreamError.failedOnRead
}
if numberBytesRead == 0 {
free(unsafeMutableRawPointer)
return nil
}
let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead)
let results = Array<UInt8>(unsafeBufferPointer)
free(unsafeMutableRawPointer)
return results
}

