C语言初等函数,C中的基本类型和基本函数在Swift中是如何表示的

自从Swift开源并被移植到更多平台之后,一个日益显现的问题就是它需要更多地和C进行混编,调用OS API也好,使用第三方程序库也好。

因此,接下来的一个话题就是,从各种基础类型、struct、函数、指针到OC对C的各种扩展,这些语言元素是如何桥接到Swift的呢?这个系列里,我们就通过一些实际的场景来了解Swift和C交互的方式。

C语言中的基础类型

首先要介绍的,是C中的基础类型,大家可以在这里

找到完整的基本类型对应表,简单来说,就是对C中的类型采取驼峰式命名之后,加上前缀字母C。例如:

0b808f123ebb

CType SwiftType.png

int变成 CInt;

unsigned char变成CUnsignedChar;

unsigned long long变成CUnsignedLongLong;

其中,只有有三个表示宽字符的类型是特殊的:

wchat_t变成CWideChar;

char16_t变成CChar16;

char32_t变成CChar32;

于是,在Swift里,我们可以直接使用这些类型来定义变量,例如:

let cInt: CInt = 10

let cChar: CChar = 49

在Xcode里按住option点击这些类型就会看到,它们都是typealias。例如,CInt的定义是这样的:

typealias CInt = Int32

但是,即便我们知道了这些C类型对应的Swift类型,当和C代码交互的时候,我们也应该总是使用这些类型的typealias版本,而不要直接使用这些别名对应的原生类型。

traditional_oc.h

#ifndef traditional_oc_h

#define traditional_oc_h

#import

//导入基本类型的全局变量

const int global_ten;

//NS_STRING_ENUM修饰的类型,通常表示某个范围里,值固定的类型

typedef NSString * TrafficLightColor NS_STRING_ENUM;

TrafficLightColor const TrafficLightColorRed;

TrafficLightColor const TrafficLightColorYellow;

TrafficLightColor const TrafficLightColorGreen;

//如果一个类型的值有可能扩展,我们可以使用`NS_EXTENSIBLE_STRING_ENUM`来修饰它

typedef int Shape NS_EXTENSIBLE_STRING_ENUM;

Shape const ShapeCircle;

Shape const ShapeTriangle;

Shape const ShapeSquare;

int add(int m, int n);

int sum(int count, ...);

int vsum(int count, va_list numbers);

#endif

traditional_oc.m

#import "traditional_oc.h"

const int global_ten = 10;

TrafficLightColor const TrafficLightColorRed = @"Red";

TrafficLightColor const TrafficLightColorYellow = @"Yellow";

TrafficLightColor const TrafficLightColorGreen = @"Green";

Shape const ShapeCircle = 1;

Shape const ShapeTriangle = 2;

Shape const ShapeSquare = 3;

int add(int m, int n) {

return m + n;

}

int sum(int count, ...) {

va_list ap;

int s = 0;

va_start(ap, count);

vsum(count, ap);

va_end(ap);

return s;

}

int vsum(int count, va_list numbers) {

int s = 0;

int i = 0;

for (; i < count; ++i) {

s += va_arg(numbers, int);

}

return s;

}

main.swift

import Foundation

let ten = global_ten

/*

对于用NS_STRING_ENUM修饰的TrafficLightColor,引入到Swift就会变成一个类似这样的struct:

struct TrafficLightColor: RawRepresentable {

typealias RawValue = String

init(rawValue: RawValue)

var rawValue: RawValue { get }

static var red: TrafficLightColor { get }

static var yellow: TrafficLightColor { get }

static var green: TrafficLightColor { get }

}

这个转换规则是这样的:

根据NS_STRING_ENUM修饰的类型决定导入到Swift时struct的名字,因此,导入的类型名称就是TrafficLightColor;

去掉和类型名称相同的公共前缀,并把剩余部分首字母小写后,变成struct的type property;

*/

let redColor: TrafficLightColor = .red

let redColorRawValue = redColor.rawValue // Red

//这样,按照之前的逻辑,类型Shape在Swift中会被导入成一个struct,它和TrafficLight唯一不同的地方在于,多了一个可以省略参数的init方法,使得我们可以在Swift里,这样扩展Shape的值:

extension Shape {

static var ellipse: Shape {

return Shape(4)

}

}

let e: Shape = .ellipse

//当然,这并不是说使用NS_STRING_ENUM导入的类型就不可以扩展,例如,我们也可以在Swift里,这样扩展TrafficLightColor:

extension TrafficLightColor {

static var blue: TrafficLightColor {

return TrafficLightColor(rawValue: "Blue")

}

}

//从语法上来说,这没有任何问题。因此,NS_STRING_ENUM和NS_EXTENSIBLE_STRING_ENUM并不是什么语言层面上的限制,而只是语义上的差别。面对这种差别,Swift为NS_EXTENSIBLE_STRING_ENUM提供了更为方便的扩展方法罢了。

基本函数是如何做桥接的

在Swift里,add会变成这样:

func add(_ m: Int32, _ n: Int32) -> Int32 {

return m + n

}

其中有两点需要注意:

C中桥街过来的函数默认都是省略external name的;

C中的int会自动转换成Int32,因此默认是不能传递Swift Int类型的,只能使用CInt类型;

let sum = add(32, 23)

它们都是很简单的C代码,如果你还不熟悉C的可变参数函数,可以先在这里简单了解下,我们就不重复了。这两个函数会如何桥接到Swift呢?遗憾的是,Swift只能接受vsum,而不能接受sum。也就是说,无论如何都无法在Swift中直接调用sum函数。而vsum桥接到Swift之后,是这样的:

func vsum(count: Int32, numbers: CVaListPointer) -> Int32

因此,在Swift里,我们不能像vsum(6, 1, 2, 3, 4, 5, 6)这样调用vsum,那么这个CVaListPointer是什么呢?简单来说,它就是C中va_list桥接到Swift后对应的类型。为了得到这个对象,我们有两种方法。

第一种,是调用getVaList方法,并把要传递的可变参数作为一个数组传递给它:

let vaListPointer = getVaList([1, 2, 3, 4, 5, 6])

let sum1 = vsum(6, vaListPointer)

这样,我们就可以把vaListPointer作为vsum的第二个参数了。

第二种,是调用withVaList方法,它的第一个参数是一个数组,我们像调用getVaList一样把所有可变参数传递给它;第二个参数是一个closure,withVaList会根据第一参数中的所有成员,生成一个对应的CVaListPointer对象,并传递给这个closure。因此,我们只要在closure里调用vsum就好了:

let sum2 = withVaList([1, 2, 3, 4, 5, 6]) {

vaListPointer in

vsum(6, vaListPointer)

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值