Major 64-Bit Changes

March 4, 2015

数据类型的变化

在C和Objective-C语言里,每个平台(编译器)都自己定义了内建数据类型的一些内存属性(大小,对齐方式), 并没有一个统一的标准。这样做的好处是在于在语言标准的的严格定义下,每个平台可以让数值在操作系统和硬件下更好的适配。 iOS 64-bit 运行时也对很多内建数据类型的大小做了改变。在上层,很多 Cocoa Touch frameworks 使用的数据类型也做了改变。

ILP32和LP64

32-bit运行时表示为ILP32
其中,I表示整型;L表示长整型;P代表指针;ILP32表示在32-bit运行是里,整型、长整型、指针时32-bit长度 同理LP64则表示在64-bit运行时里 整型是32-bit长度;长整型、指针为64-bit长度

下表描述了OC代码里常用的整数类型,介绍了各个类型在不同的运行时下占用的大小。LP64和ILP32的不同之处用高亮表示了出来,这些大小区别表明了在64-bit运行时的改变。编译器用__LP64__宏表明64-bit运行时

总结:

  • 指针类型的大小由原来的4 bytes增加到了8 bytes
  • 长整型、size_t、CFIndex、和 NSInteger的大小由4 bytes增加到了8 bytes

应对应用中数据类型的改变

当我们在编译同事支持32-bit和64-bit的app时,我们需要格外注意运行环境对app产生的性能和一些兼容性问题。此处列举几条供大家参考
1. 增长的内存消耗
由于很多数据类型的占用空间都由之前的32-bit增长到了64-bit,所以我们的应用在运行时所占的内存也会增加。预计会在优化性能上耗费更多是的时间,甚至在设计数据结构时得考虑不同的策略
2. 32-bit软件和64-bit软件之间的数据传递
如果你出货32位和64位软件,有时两个版本需要互相操作相同的数据。例如,用户可能访问来自32位和64位设备中存储的iCloud一个文件。或者你可能会创建一个游戏,发送设备之间的网络数据。在这两个运行时,确保该数据被读取或写入使用一个共用存储器的布局,这意味着尺寸和每一个数据元素的偏移量是相同的。
3. 数值计算可能得到不同的结果
由于64-bit中整型由原有的4字节变成了8字节,如果我们的应用从32-bit变成64-bit就有可能得到不同的结果。因为当我们的一个很大的数字在32-bit中可能会产生数据溢出,而在64-bit中则不会
4. 数据截断
当我们将一个大数据拷贝到一个相对小点的数据中时,有可能会发生数据溢出。系统会将数据截断,已保证存储。例如将一个NSInteger赋值给int,在32-bit系统中可以正常工作,而在64-bit系统中,则会被截断

方法调用的改变

当一个方法被调用时,编译器触发代码从调用者和被接受者之间传递参数。例如,ABI可能就爱那个调用者所传递的参数存放在寄存器中或者存放在栈中。通常情况下,如果我们不写汇编语言,我们基本上不用太关注这些方法调用的规则。但在64位运行时,有时你需要知道方法是如何被调用的。调用可变数量的参数(可变参数的函数)的方法和固定参数的方法使用的规则是不同的

对应用程序调用的影响

当我们编写一个64-bit应用时,我们的应用调用的每一个方法必须要有准确的定义

  1. 每个方法必须有声明
  2. 当我们在对一个方法做类型转换时,我们必须保证转换前后的函数有相同的签名。特别的,不能将两个拥有不同参数的函数类型进行转换

Objective-C的改变

不能在直接调用isa,如果需要的话,可以通过运行时方法来获取

总结

为了保证我们完全的适配64-bit,我们需要注意以下几点

  1. 避免将64-bit的long赋值给32-bit的整型
  2. 避免将64-bit的指针赋值给32-bit的指针
  3. 避免在算术运算时指针和长整数截断
  4. 修复程序问题引起变化的数据类型的大小调整问题
  5. 确保是在32位和64位的运行时之间共享的存储器的结构具有相同的布局
  6. 重写汇编语言代码,确保我们的代码使用新的64-bit操作码和运行
  7. 避免将可变参数的函数类型转换为不可变参数的函数类型,或者反之亦然功能

Comments