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语言 ...
随机推荐
- MySQL运行内存不足时应采取的措施
导读 排除故障指南:MySQL运行内存不足时应采取的措施? 原文出处:<What To Do When MySQL Runs Out of Memory: Troubleshooting Gui ...
- Python urllib Request 用法
转载自:https://blog.csdn.net/ywy0ywy/article/details/52733839 python2.7 httplib, urllib, urllib2, reque ...
- 【Java】 剑指offer(32) 从上往下打印二叉树
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺 ...
- hdu 4738 Caocao's Bridges 求无向图的桥【Tarjan】
<题目链接> 题目大意: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.周瑜为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸 ...
- SAC#1 - 组合数
P3414 SAC#1 - 组合数 组合数的性质,求(1<<(n-1))%mod即可.其实要快速幂. #include<bits/stdc++.h> #define MOD 6 ...
- 008.Docker Flannel+Etcd分布式网络部署
一 环境准备 1.1 Flannel概述 Flannel是一种基于overlay网络的跨主机容器网络解决方案,即将TCP数据包封装在另一种网络包里面进行路由转发和通信,Flannel是CoreOS开发 ...
- JS高级-原型等概念深入理解
一 数据类型: 基本(值)数据类型: string number undefined null boolean 对象(引用)类型 [ 查找对象的属性时,会查找原型链 设置属性时,一般在构造函数里面设置 ...
- 条件随机场之CRF++源码详解-训练
上篇的CRF++源码阅读中, 我们看到CRF++如何处理样本以及如何构造特征.本篇文章将继续探讨CRF++的源码,并且本篇文章将是整个系列的重点,会介绍条件随机场中如何构造无向图.前向后向算法.如何计 ...
- SQL server学习(五)T-SQL编程之存储过程
周五了,祝大家周末愉快. 之前一直在写SQL server的分享,今天再来个T-SQL编程中的存储过程. 存储过程 存储过程(procedure)类似于C语言中的函数,用来执行管理任务或应用复杂的业务 ...
- python处理转义字符
python2 #1. import HTMLParser HTMLParser.HTMLParser().unescape('Suzy & John') #2. from xml.sax.s ...