Swift 与 C 语言混合编程
前言
- 作为一种可与 Objective-C 相互调用的语言,Swift 也具有一些与 C 语言的类型和特性,如果你的代码有需要,Swift 也提供了和常见的 C 代码结构混合编程的编程方式。
1、基本数据类型
Swift 提供了一些和 C 语言的基本类型如
char,int,float,double等价的 Swift 基本数据类型。然而,这些 Swift 的核心基本类型之间并不能隐式的相互转换,如Int。因此,只有你的代码明确要求它们时再使用这些类型,而Int可以在任何你想使用它的时候使用。C 类型 Swift 类型 boolCBoolchar, signed charCCharunsigned charCUnsignedCharshortCShortunsigned shortCUnsignedShortintCIntunsigned intCUnsignedIntlongCLongunsigned longCUnsignedLonglong longCLongLongunsigned long longCUnsignedLongLongwchar_tCWideCharchar16_tCChar16char32_tCChar32floatCFloatdoubleCDouble
2、枚举
Swift 引进了用宏
NS_ENUM来标记的任何 C 风格的枚举类型。这意味着无论枚举值是在系统框架还是在自定义的代码中定义的,当他们导入到 Swift 时,他们的前缀名称将被截断。Swift 也引进了标有
NS_OPTIONS宏选项。而选项的行为类似于引进的枚举,选项还可以支持一些位操作,如&,| 和 ~。在 Objective-C 中,你用一个空的选项设置标示恒为零 (0)。在 Swift 中,使用 nil 代表没有任何选项。
看这个 Objective-C 枚举
// Objective-C typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
在 Swift 中这样来实现
// Swift enum UITableViewCellStyle: Int { case Default
case Value1
case Value2
case Subtitle
}
当你需要指向一个枚举值时,使用以点 (.) 开头的枚举名称
// Swift let cellStyle: UITableViewCellStyle = .Default
3、指针
Swift 尽可能避免让你直接访问指针。然而,当你需要直接操作内存的时候,Swift 也为你提供了多种指针类型。下面的表使用 Type 作为占位符类型名称来表示语法的映射。
对于参数,使用以下映射:
C 句法 Swift 句法 const void *CConstVoidPointervoid *CConstPointer<Type>const Type *CUnsignedCharType *CMutablePointer<Type>对于返回类型,变量和参数类型的多层次指针,使用以下映射:
C 句法 Swift 句法 void *COpaquePointerType *UnsafePointer<Type>对于类(class)类型,使用以下映射:
C 句法 Swift 句法 Type * const *CConstPointer<Type>Type * __strong *CMutablePointer<Type>Type **AutoreleasingUnsafePointer<Type>
3.1 C 可变指针
当一个函数被声明为接受
CMutablePointer<Type>参数时,这个函数可以接受下列任何一个类型作为参数。nil,作为空指针传入一个
CMutablePointer<Type>类型的值一个操作数是
Type类型的左值的输入输出表达式,作为这个左值的内存地址传入一个输入输出
Type[]值,作为一个数组的起始指针传入,并且它的生命周期将在这个调用期间被延长如果你像这样声明了一个函数
// Swift func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }
那么你可以使用以下任何一种方式来调用这个函数
// Swift var x: Float = 0.0
var p: CMutablePointer<Float> = nil
var a: [Float] = [1.0, 2.0, 3.0] takesAMutablePointer(nil)
takesAMutablePointer(p)
takesAMutablePointer(&x)
takesAMutablePointer(&a)
当函数被声明使用一个
CMutableVoidPointer参数,那么这个函数接受任何和CMutablePointer<Type>相似类型的Type操作数。如果你这样定义了一个函数
// Swift func takesAMutableVoidPointer(x: CMutableVoidPointer) { /*...*/ }
那么你可以使用以下任何一种方式来调用这个函数
// Swift var x: Float = 0.0, y:Int = 0
var p: CMutablePointer<Float> = nil, q: CMutablePointer<Int> = nil
var a: [Float] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3] takesAMutableVoidPointer(nil)
takesAMutableVoidPointer(p)
takesAMutableVoidPointer(q)
takesAMutableVoidPointer(&x)
takesAMutableVoidPointer(&y)
takesAMutableVoidPointer(&a)
takesAMutableVoidPointer(&b)
3.2 C 常指针
当一个函数被声明为接受
CConstPointer<Type>参数时,这个函数可以接受下列任何一个类型作为参数。nil,作为空指针传入一个
CMutablePointer<Type>,CMutableVoidPointer,CConstPointer<Type>,CConstVoidPointer,或者在必要情况下转换成CConstPointer<Type>的AutoreleasingUnsafePointer<Type>值一个操作数是
Type类型的左值的输入输出表达式,作为这个左值的内存地址传入一个
Type[]数组值,作为一个数组的起始指针传入,并且它的生命周期将在这个调用期间被延长如果你这样定义了一个函数
// Swift func takesAConstPointer(x: CConstPointer<Float>) { /*...*/ }
那么你可以使用以下任何一种方式来调用这个函数
// Swift var x: Float = 0.0
var p: CConstPointer<Float> = nil takesAConstPointer(nil)
takesAConstPointer(p)
takesAConstPointer(&x)
takesAConstPointer([1.0, 2.0, 3.0])
当函数被声明使用一个
CConstVoidPointer参数,那么这个函数接受任何和CConstPointer<Type>相似类型的Type操作数。如果你这样定义了一个函数
// Swift func takesAConstVoidPointer(x: CConstVoidPointer) { /*...*/ }
那么你可以使用以下任何一种方式来调用这个函数
// Swift
var x: Float = 0.0, y: Int = 0
var p: CConstPointer<Float> = nil, q: CConstPointer<Int> = nil takesAConstVoidPointer(nil)
takesAConstVoidPointer(p)
takesAConstVoidPointer(q)
takesAConstVoidPointer(&x)
takesAConstVoidPointer(&y)
takesAConstVoidPointer([1.0, 2.0, 3.0])
takesAConstVoidPointer([1, 2, 3])
3.3 自动释放不安全指针
当一个函数被声明为接受
AutoreleasingUnsafePointer<Type>参数时,这个函数可以接受下列任何一个类型作为参数。nil,作为空指针传入一个
AutoreleasingUnsafePointer<Type>值其操作数是原始的,复制到一个临时的没有所有者的缓冲区的一个输入输出表达式,该缓冲区的地址传递给调用,并返回时,缓冲区中的值加载,保存,并重新分配到操作数。
注意:这个列表没有包含数组。
如果你这样定义了一个函数
// Swift func takesAnAutoreleasingPointer(x: AutoreleasingUnsafePointer<NSDate?>) { /*...*/ }
那么你可以使用以下任何一种方式来调用这个函数:
// Swift var x: NSDate? = nil
var p: AutoreleasingUnsafePointer<NSDate?> = nil takesAnAutoreleasingPointer(nil)
takesAnAutoreleasingPointer(p)
takesAnAutoreleasingPointer(&x)
注意:C 语言函数指针没有被 Swift 引进。
4、全局常量
- 在 C 和 Objective-C 语言源文件中定义的全局常量会自动地被 Swift 编译引进并做为 Swift 的全局常量。
5、预处理指令
- Swift 编译器不包含预处理器。取而代之的是它充分利用了编译时属性生成配置和语言特性来完成相同的功能。因此 Swift 没有引进预处理指令。
5.1 简单宏
在 C 和 Objective-C 中通常使用的
#define指令定义的一个宏常数,在 Swift 中可以使用全局常量来代替。由于简单的用于定义常量的宏会被直接被映射成 Swift 全局量,Swift 编译器会自动引进在 C 或 Objective-C 源文件中定义的简单宏。例如: 一个全局定义
#define FADE_ANIMATION_DURATION 0.35,在 Swift可以使用let FADE_ANIMATION_DURATION = 0.35来更好的表述。
5.2 复杂宏
- 在 C 和 Objective-C 中使用的复杂宏在 Swift 中并没有与之对应的定义。复杂宏是那些不用来定义常量的宏,而是用来定义包含小括号 () 函数的宏。你在 C 和 Objective-C 使用复杂的宏是用来避免类型检查的限制和相同代码的重复劳动。然而,宏也会产生 Bug 和重构的困难。在 Swift 中你可以直接使用函数和泛型来达到同样的效果。因此,在 C 和 Objective-C 源文件中定义的复杂宏在 Swift 是不能使用的。
5.3 编译配置
Swift 代码和 Objective-C 代码以不同的方式进行条件编译。Swift 代码可以根据生成配置的评价配进行有条件的编译。生成配置包括
true和false字面值,命令行标志,和下表中的平台测试函数。你可以使用-D <#Flag#>指定命令行标志。函数 有效参数 os()OSX, iOSarch()x86_64, arm, arm64, i386- 注意:
arch(arm)的生成配置不会为 64 位 arm 设备返回true,当代码运行在为 32 位的 iOS 模拟器器时,arch(i386)的生成配置返回true。
- 注意:
一个简单的条件编译需要以下代码格式。
#if build configuration
statements
#else
statements
#endif
一个由零个或多个有效的 Swift 语句声明的
statements,可以包括表达式,语句和控制流语句。你可以添加额外的构建配置要求,条件编译说明用&&和||操作符以及!操作符,添加条件控制块用#elseif。#if build configuration && !build configuration
statements
#elseif build configuration
statements
#else
statements
#endif
与 C 语言编译器的条件编译相反,Swift 条件编译语句必须完全是自包含和语法有效的代码块。这是因为 Swift 代码即使没有被编译,也要全部进行语法检查。
Swift 与 C 语言混合编程的更多相关文章
- 【转载】ANSYS的APDL与C语言混合编程(实例)
原文地址:http://www.cnblogs.com/lyq105/archive/2010/05/04/1727557.html 本文讨论的不是利用C语言为ANSYS写扩展(或者说是用户子程序), ...
- Java语言与C语言混合编程(2)--在Java中调用C语言本地库
在上一篇文章中介绍了Java语言中的native关键字,以及Java语言调用C语言的编译生成本地动态链接库(DLL)实现加法运算的小例子,本文通过一个更加详细的例子,深入讲解Java语言调用C语言的函 ...
- Java语言与C语言混合编程(1)--Java native 关键字
一. 什么是 native Method 简单地讲,一个 native Method 就是一个java调用非java代码的接口.一个 native Method 是这样一个java的方法:该方法的实现 ...
- Android程序中,内嵌ELF可执行文件-- Android开发C语言混合编程总结
前言 都知道的,Android基于Linux系统,然后覆盖了一层由Java虚拟机为核心的壳系统.跟一般常见的Linux+Java系统不同的,是其中有对硬件驱动进行支持,以避开GPL开源协议限制的HAL ...
- iOS - Swift 与 C 语言交互编程
前言 作为一种可与 Objective-C 相互调用的语言,Swift 也具有一些与 C 语言的类型和特性,如果你的代码有需要,Swift 也提供了和常见的 C 代码结构混合编程的编程方式. 1.基本 ...
- Dart 调用C语言混合编程
Dart 调用C语言本篇博客研究Dart语言如何调用C语言代码混合编程,最后我们实现一个简单示例,在C语言中编写简单加解密函数,使用dart调用并传入字符串,返回加密结果,调用解密函数,恢复字符串内容 ...
- SQL+C#:一次多语言混合编程的经验总结
1.用JAVA做,采取轮询策略: 2.用sql语言+C#混合编程,采取触发策略
- Swift语言与Objective-C语言混合编程
首先创建一个Swift的Single View工程 然后直接在工程中新建OC文件: 然后选择OC语言之后会问你是否自动创建OC和Swift的中间文件: 然后工程文件夹里就有了三个文件: 现在OC头文件 ...
- 《从零开始学Swift》学习笔记(Day 71)——Swift与C/C++混合编程之数据类型映射
原创文章,欢迎转载.转载请注明:关东升的博客 如果引入必要的头文件,在Objective-C语言中可以使用C数据类型.而在Swift语言中是不能直接使用C数据类型,苹果公司为Swift语言提供与C语言 ...
随机推荐
- 快速构建ceph可视化监控系统
https://my.oschina.net/colben/blog/1844602 https://my.oschina.net/u/3626804/blog/1859613
- (第4篇)hadoop之魂--mapreduce计算框架,让收集的数据产生价值
摘要: 通过前面的学习,大家已经了解了HDFS文件系统.有了数据,下一步就要分析计算这些数据,产生价值.接下来我们介绍Mapreduce计算框架,学习数据是怎样被利用的. 博主福利 给大家赠送一套ha ...
- POJ 2393 Yogurt factory【贪心】
POJ 2393 题意: 每周可以生产牛奶,每周生产的价格为Ci,每周需要上交的牛奶量Yi,你可以选择本周生产牛奶,也可选择提前几周生产出存储在仓库中(仓库无限大,而且保质期不考虑),每一周存仓库牛奶 ...
- MySQL运行内存不足时应采取的措施
导读 排除故障指南:MySQL运行内存不足时应采取的措施? 原文出处:<What To Do When MySQL Runs Out of Memory: Troubleshooting Gui ...
- BZOJ1088 [SCOI2005]扫雷Mine 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1088 题意概括 扫雷.只有2行.第2行没有雷,第一行有雷.告诉你第二行显示的数组,问有几种摆放方式 ...
- 机器学习数据处理时label错位对未来数据做预测
这篇文章继上篇机器学习经典模型简单使用及归一化(标准化)影响,通过将测试集label(行)错位,将部分数据作为对未来的预测,观察其效果. 实验方式 以不同方式划分数据集和测试集 使用不同的归一化(标准 ...
- Golang vs PHP 之文件服务器
前面的话 作者为golang脑残粉,本篇内容可能会引起phper不适,请慎读! 前两天有同事遇到一个问题,需要一个能支持上传.下载功能的HTTP服务器做一个数据中心.我刚好弄过,于是答应帮他搭一个. ...
- Session丢失的解决方法
1.修改配置文件 <sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:4 ...
- BZOJ.4566.[HAOI2016]找相同字符(后缀数组 单调栈)
题目链接 给定两个字符串,求它们有多少个相同子串.相同串的位置不同算多个. POJ3145简化版. 后缀自动机做法见这儿,又快又好写(一下就看出差距了..) //13712kb 4076ms #inc ...
- [BZOJ4987]Tree
题目大意: 给定一棵\(n(n\le3000)\)个点的带边权的树,找出\(k\)个点\(A_{1\sim k}\)使得\(\sum_{1\le i<k} dis(A_i,A_i+1)\)最小. ...