在现阶段Swift的编码中,我们还是有很多场景需要调用一些C函数。在Swift与C的混编中,经常遇到的一个问题就是需要在两者中互相转换字符串。在C语言中,字符串通常是用一个char数组来表示,在Swift中,是用CChar数组来表示。从CChar的定义可以看到,其实际上是一个Int8类型,如下所示:

1
2
3
4
5
/// The C 'char' type.
///
/// This will be the same as either `CSignedChar` (in the common
/// case) or `CUnsignedChar`, depending on the platform.
public typealias CChar = Int8

如果我们想将一个String转换成一个CChar数组,则可以使用String的cStringUsingEncoding方法,它是String扩展中的一个方法,其声明如下:

1
2
3
4
/// Returns a representation of the `String` as a C string
/// using a given encoding.
@warn_unused_result
public func cStringUsingEncoding(encoding: NSStringEncoding) -> [CChar]?

参数指定的是编码格式,我们一般指定为NSUTF8StringEncoding,因此下面这段代码:

1
2
3
let str: String = "abc1个"
// String转换为CChar数组
let charArray: [CChar] = str.cStringUsingEncoding(NSUTF8StringEncoding)!

其输出结果是:

1
[97, 98, 99, 49, -28, -72, -86, 0]

可以看到"个"字由三个字节表示,这是因为Swift的字符串是Unicode编码格式,一个字符可能由1个或多个字节组成。另外需要注意的是CChar数组的最后一个元素是0,它表示的是一个字符串结束标志符\n。

我们知道,在C语言中,一个数组还可以使用指针来表示,所以字符串也可以用char *来表示。在Swift中,指针是使用UnsafePointer或UnsafeMutablePointer来包装的,因此,char指针可以表示为UnsafePointer,不过它与[CChar]是两个不同的类型,所以以下代码会报编译器错误:

1
2
// Error: Cannot convert value of type '[CChar]' to specified type 'UnsafePointer'
let charArray2: UnsafePointer = str.cStringUsingEncoding(NSUTF8StringEncoding)!

不过有意思的是我们可以直接将String字符串传递给带有UnsafePointer参数的函数或方法,如以下代码所示:

1
2
3
4
5
func length(s: UnsafePointer) {
    print(strlen(s))
}
length(str)
// 输出:7\n

而String字符串却不能传递给带有[CChar]参数的函数或方法,如以下代码会报错误:

1
2
3
4
5
func length2(s: [CChar]) {
    print(strlen(s))
}
// Error: Cannot convert value of type 'String' to expected argument type '[CChar]'
length2(str)

实际上,在C语言中,我们在使用数组参数时,很少以数组的形式来定义参数,则大多是通过指针方式来定义数组参数。

如果想从[CChar]数组中获取一上String字符串,则可以使用String的fromCString方法,其声明如下:

1
2
3
4
5
6
7
/// Creates a new `String` by copying the nul-terminated UTF-8 data
/// referenced by a `CString`.
///
/// Returns `nil` if the `CString` is `NULL` or if it contains ill-formed
/// UTF-8 code unit sequences.
@warn_unused_result
public static func fromCString(cs: UnsafePointer) -> String?

从注释可以看到,它会将UTF-8数据拷贝以新字符串中。如下示例:

1
2
3
let chars: [CChar] = [99, 100, 101, 0]
let str2: String = String.fromCString(chars)!
// 输出:cde

这里需要注意的一个问题是,CChar数组必须以0结束,否则会有不可预料的结果。在我的Playground示例代码中,如果没有0,报了以下错误:

1
Execution was interrupted. reason: EXC_BAD_INSTRUCTION

还有可能出现的情况是CChar数组的存储区域正好覆盖了之前某一对象的区域,这一对象有一个可以表示字符串结尾的标识位,则这时候,str2输出的可能是"cde1一"。

小结

在Swift中,String是由独立编码的Unicode字符组成的,即Character。一个Character可能包括一个或多个字节。所以将String字符串转换成C语言的char *时,数组元素的个数与String字符的个数不一定相同(即在Swift中,与str.characters.count计算出来的值不一定相等)。这一点需要注意。另外还需要注意的就是将CChar数组转换为String时,数组最后一个元素应当为字符串结束标志符,即0。

Swift 中 String 与 CChar 数组的转换的更多相关文章

  1. Swift中String与NSDate的互相转换

    其实每种编程语言,我都觉得String和日期对象的相互转换是一种十分麻烦的事情,Swift也不例外.这篇博客记录了我学到的String与NSDate的互相转换方法,供大家参考. 从String转为NS ...

  2. Swift 中 String 取下标及性能问题

    Swift 中 String 取下标及性能问题 取下标 String String 用 String.Index 取下标(subscript)得到 Character,String.Index 要从 ...

  3. Swift中String和NSString的一个不同之处

    我们知道在Swift中String和NSString是可以互相转换使用的-额-应该是在绝大数情况下可以互相转换使用.在某些情况下可能还有一丝丝略微的差别:比如在涉及到处理字符串中字符索引的时候. 我们 ...

  4. [ios][swift]swift中如果做基本类型的转换

    在swift中如果做基本类型的转换的?比如Int -> Float(Double)Double -> 保留两位小数String -> IntDouble -> String 有 ...

  5. Java中String和byte[]间的转换浅析

    Java语言中字符串类型和字节数组类型相互之间的转换经常发生,网上的分析及代码也比较多,本文将分析总结常规的byte[]和String间的转换以及十六进制String和byte[]间相互转换的原理及实 ...

  6. Java中String和byte[]间的 转换浅析

    Java语言中字符串类型和字节数组类型相互之间的转换经常发生,网上的分析及代码也比较多,本文将分析总结常规的byte[]和String间的转换以及十六进制String和byte[]间相互转换的原理及实 ...

  7. Java中String和byte[]间的 转换

    数据库的字段中使用了blob类型时,在entity中此字段可以对应为byte[] 类型,保存到数据库中时需要把传入的参数转为byte[]类型,读取的时候再通过将byte[]类型转换为String类型. ...

  8. C++11中string与数值类型的转换

    C++中string与数值类型的相互转换记录 string转int.double.long string s = "123.456"; // string -> int co ...

  9. swift 中String常用操作

    1.  字符串定义 var s = "aaaaaa" // 两个字符串均为空并等价. var emptyString = ""   var anotherEmp ...

随机推荐

  1. 聪明的质监员(codevs 1138)

    题目描述 Description 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n 个矿石,从1到n 逐一编号,每个矿石都有自己的重量wi 以及价值vi.检验矿产的流程是:见图   ...

  2. [Xcode 实际操作]八、网络与多线程-(19)使用RunLoop使PerformSelector方法延迟动作的执行

    目录:[Swift]Xcode实际操作 本文将演示使用RunLoop使PerformSelector方法延迟动作的执行. 在项目导航区,打开视图控制器的代码文件[ViewController.swif ...

  3. 简单搭建webMagic爬虫步骤

    1.简介 WebMagic是一个简单灵活的Java爬虫框架.基于WebMagic,你可以快速开发出一个高效.易维护的爬虫. 官网:http://webmagic.io/ 中文官网:http://web ...

  4. SpringMVC注解校验

    spring注解式参数校验     版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/jinzhencs/article/details/5168283 ...

  5. docker+jenkins实现持续集成

    持续集成的概念我就不多说了,网上一大堆,今日主要讲讲怎么通过docker 和jenkins实现项目的持续集成.看着简单,网上完整教程很少,本人摸索很久才搞定!!! 一.首先安装docker.安装过程可 ...

  6. web.xml中一个filter配置多个url-pattern

    需要在filter标签后添加多个filter-mapping标签,一个url-pattern就对应一个filter-mapping标签,不能直接把多个url-pattern配置到同一个filter-m ...

  7. js截取文件名不带后缀

    利用正则表达式是匹配后缀名 一般文件后缀都为.xxx,也就是说从尾部匹配的话首先是字母,接着应该有一个. 那么我们就开始写正则表达式 利用在线工具 方便我们编写边测试 一般都是小写字母,所以我们用[a ...

  8. SpirngMVC-JSON

    Springmvc默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包,如下: 配置json转换器 在注解适配器中加入messa ...

  9. java中的线程安全是什么?什么叫线程安全?什么叫不安全?

    java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问 什么叫 ...

  10. 解决win64无法添加curl扩展的问题

    网上试了很多方法都无效,最后直接用phpstudy集成安装包中对应版本的php_curl.dll替换即可