64位和32位区别 ios_ios 32位 64位区别 - CSDN
  • 苹果于2013年9月推出了iPhone 5S新手机,采用的全新A7处理器其最大特色就是支持64位运算。其64位A7处理器的使用意味着iPhone性能会大有提高,性能...Xcode 5编译的iOS 7程序包含了32位和64位两套进制代码,在32位的i

    苹果于2013年9月推出了iPhone 5S新手机,采用的全新A7处理器其最大特色就是支持64位运算。其64位A7处理器的使用意味着iPhone性能会大有提高,性能和速度更加出色;而要到达到这样的性能,开发者就要开发64位的应用了。

    一、讨论宏观问题

    1. 1

      Xcode 5编译的iOS 7程序包含了32位和64位两套二进制代码,在32位的iOS系统上会调用32位的二进制代码,在64位系统上会调用64位的二进制代码,以此来解决向后兼容的问题。同时,考虑到很多32位的程序可能在没有重新编译的情况下部署到64位系统上,64位的iOS系统中带有两套FrameWork,一套是32位的,一套是64位的。当64位的iOS系统运行原来的32位程序时,系统会调用32位的FrameWork作为底层支撑,当系统运行64位程序时,系统会调用64位的FrameWork作为底层支撑。也就是说,当一个iPhone 5S上同时运行32位程序和64位程序时,系统同时将32位和64位两套FrameWork载入了内存中,所以消耗的内存也比较多。如果一台64位的iOS设备上运行的所有程序都是为64位系统编译过的,iOS系统将只载入64位的FrameWork,这将节省好多内存。所以,如果大家都可以快速将程序传换成64位的,iOS将跑得更快。

      END

    二、讨论细节问题

    1. 1

      32位的iOS系统和64位的iOS系统主要的差别有两个,一个是数据类型的差别,一个是过程调用方法的差别。在数据类型上,主要的变化是指针类型(Pointer)和长整数类型(long)的长度变化和内存对齐方式的变化,同时也导致了更高级别数据类型的变化,如NSInteger的长度也有变化。在过程调用方法上,因为ARM V8 和ARM V7具有不同数量的寄存器,具有不同的过程调用约定,所以32位系统和64位系统在汇编层级是不同的。

      END

    总结:

    • 开发人员根据以下要点来检查原来的32位代码就可以将应用移植到64位系统上了:1. 不要将长整型数据(long)赋予整型(int)这种代码在32位系统上没有问题,因为在32位系统中long和int的长度是一样的,不过在64位系统中就有可能出问题,因为64位系统中long比int长,将long值赋予int将导致数据丢失。2. 不要将指针类型(Pointer)赋予整型(int)为 了方便地址计算,有时程序员会将指针类型赋予整型,这种代码在32位系统上没有问题,因为在32位系统中Pointer和int的长度是一样的,不过在 64位系统中就会有问题,因为64位系统中Pointer比int长,将Pointer值赋予int将导致地址数据丢失,最终导致严重问题。3. 留意那些和数位相关的数值计算比如掩码技术,如果使用一个long类型的掩码,转到64位系统后高位都是0,计算出来的结果可能不符合预期。还有无符号整数和有符号整数的混用等。4. 留意对齐方式带来的变化如果在32位系统上定义一个结构包含两个long类型,第二个long数值的偏移地址是4,可以通过结构地址+4的方式获取,但是在64位系统上就不行了,因为在64位系统中第二个long数值的偏移地址是8。5. 充分考虑在32位应用和64位应用之间的数据交换因 为用户会通过网络交换数据,同时用户保存的数据也可能通过备份等方式在32位系统和64位系统之间切换,所以应用在保存和发送流数据的时候一定要考虑充 分。比如数据在32位系统中保存,在64位系统中能否正常打开,或者反过来,在64位系统中保存,在32位系统中打开是否正常。6. 重写所有汇编代码这点无需说明,如果你在代码中嵌入了汇编代码,你需要参考64位系统的指令集重写汇编代码。7. 不要将可变参数的过程强制转换为定参过程,也不要将定参过程强制转换为可变参数的过程这时因为32位系统和64位系统对于这两种过程调用方式的处理方法不同。

      END

    将以前的应用编译成64位程序

    1. 1

      1. 使用Xcode 5 打开原有项目。

      2. 将支持的设备改成“iOS 7”。

      3. 在“Build Setting”中将“Architectures”改成“Standard Architectures (including 64-bit)”。

      4. 运行测试程序,解决编译过程出现的问题。


    展开全文
  • iOS32位和64位的坑

    2016-11-03 11:57:03
    在开发之前应用的时候,有一个需求是从后台请求道文件大小并显示。一时疏忽,用了int,结果数据一出,显示的是-17888... 一看到这个BUG,就意识到是数据溢出导致的。...考虑良机区别,怀疑是32位于64位区别

    在开发之前应用的时候,有一个需求是从后台请求道文件大小并显示。一时疏忽,用了int,结果数据一出,显示的是-17888...

    一看到这个BUG,就意识到是数据溢出导致的。于是改成了long,在iPadMini4上测试完美,于是提交测试。

    测试用自己的iPad4测试,结果还是-17888...,于是就懵了,

    经过跟代码,发现在iPad4上确实是溢出。

    考虑良机区别,怀疑是32位于64位区别导致的,经试验,果然是这个原因,改成long long ,解决。

    查找参考资料如下:

    C标准只规定了short至少16位,long至少32位,long long 至少64位[1],同时long long >= long >= short。[2]
    至于具体多少由编译器决定。

    对于iOS设备来说

    可用如sizeof(char),sizeof(char*)等得出

    32位编译器

    char :1个字节

    char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)

    short int : 2个字节

    int:  4个字节

    unsigned int : 4个字节

    float:  4个字节

    double:   8个字节

    long:   4个字节,最大是2147483648,在大则溢出

    long long:  8个字节

    unsigned long:  4个字节

     

    64位编译器

    char :1个字节

    char*(即指针变量): 8个字节

    short int : 2个字节

    int:  4个字节

    unsigned int : 4个字节

    float:  4个字节

    double:   8个字节

    long:   8个字节,最大是18446744073709552000

    long long:  8个字节

    unsigned long:  8个字节


    比较得知,32与64区别主要在long,64位比32位大得多。

    而在32位机器中,long与int相同,则应该尽量避免使用long,直接longlong就可以了



    展开全文
  • iOS armv7, armv7s, arm64区别与应用32位64位配置历程1、2015年2月1日不允许不支持arm64的应用的提交; 2、iOS10发布后,如果你的应用中使用到了32位的类、库,没有相应支持64位机型的库,则首次启动后会弹窗式...

    iOS armv7, armv7s, arm64区别与应用32位、64位配置

    历程

    1、2015年2月1日不允许不支持arm64的应用的提交;
    2、iOS10发布后,如果你的应用中使用到了32位的类、库,没有相应支持64位机型的库,则首次启动后会弹窗式提示:“ xxx可能使iPhone变慢…”;
    3、iOS10.3公测版发布:封杀32位应用;
    4、苹果系统(iOS7/iOS8-iOS9),32位的framework和64位的framework是共存的,所以如果所有的应用都是64位的话,系统就自动不加载32位的framework,这样可以少占用资源,另外对运行的速度是有好处的,也就是说,你会感觉手机运行的快了一点。应用在兼容64位系统后,内存的占用肯定会变多一点,不过性能也有相应的提升。

    64与32位的区别:

    数据类型的变化:

    1.在32位的年代,使用的是IPL32的规范,到了64位之后,改成了LP64规范。
    2.数据类型里面,NSInteger在32位时等同于int,在64位时等同于long,而这个数据结构使用很广,很多不规范的时候会直接和int替换使用,在32位是毫无问题,但在64位时,这就是隐患了。CGFloat也有同样的问题
    3.如果使用了偏移量来访问struct的项,那么需要认真仔细的检查,其余的还算好,当然如果你用了malloc,那么也请检查一下分配的内存大小,建议是多使用sizeof来帮助计算。
    4.方法调用上的变化:在64位系统在运行时调用函数和32位系统是不同的。主要的区别在于传递具有可变参数个数的函数的参数时,我们来看下面的代码:

    int fixedFunction(int a, int b);
    int variadicFunction(int a, …);
    int main {
    int value1 = variadicFunction(5,5);
    }

    第一个函数是固定传入2个参数,第二个函数是参数个数不定的,在使用中,也
    传入了2个参数。在32位系统下,这两个函数的参数传递是非常类似的,在64
    位系统下,这两者就是截然不同了。
    5.项目中使用的第三方库肯定需要支持64位系统,否则还是白搭。大家需要检查自己使用的第三方的库,看是否支持64位的版本。苹果系统中(iOS7/iOS8-iOS9),32位的framework和64位的framework是共存的,所以如果所有的应用都是64位的话,系统就自动不加载32位的framework,这样可以少占用资源,另外对运行的速度是有好处的,也就是说,你会感觉手机运行的快了一点。应用在兼容64位系统后,内存的占用肯定会变多一点,不过性能也有相应的提升。

    增加应用对64位的支持:

    一、配置前确认工作:

    如果你不能确定库是否支持了arm64,可以在cmd模式下用file命令来检查一下库文件
    armv7,armv7s和arm64,i386,x86_64这些都代表什么?
    -armv7|armv7s|arm64都是ARM处理器的指令集
    -i386|x86_64 是Mac处理器的指令集

    了解Arm

    Arm处理器,因为其低功耗和小尺寸而闻名,几乎所有的手机处理器都基于arm,其在嵌入式系统中的应用非常广泛,它的性能在同等功耗产品中也很出色。
    Armv6、armv7、armv7s、arm64都是arm处理器的指令集,所有指令集原则上都是向下兼容的,如iPhone4S的CPU默认指令集为armv7指令集,但它同时也兼容armv6指令集,只是使用armv6指令集时无法充分发挥其性能,即无法使用armv7指令集中的新特性,同理,iPhone5的处理器标配armv7s指令集,同时也支持armv7指令集,只是无法进行相关的性能优化,从而导致程序的执行效率没那么高。

    这些指令集在哪些设备中有用到呢?

    这里写图片描述

    -i386是针对intel通用微处理器32位处理器
    -x86_64是针对x86架构的64位处理器
    -模拟器32位处理器测试需要i386架构,
    -模拟器64位处理器测试需要x86_64架构,
    -真机32位处理器需要armv7,或者armv7s架构,
    -真机64位处理器需要arm64架构。

    Xcode Build Setting中指令集相关选项释义

    Architectures

    指定工程被编译成可支持哪些指令集类型,而支持的指令集越多,就会编译出包含多个指令集代码的数据包,对应生成二进制包就越大,也就是ipa包会变大(Space-separated list of identifiers. Specifies the architectures (ABIs, processor models) to which the binary is targeted. When this build setting specifies more than one architecture, the generated binary may contain object code for each of the specified architectures. )。

    Valid Architectures

    限制可能被支持的指令集的范围,也就是Xcode编译出来的二进制包类型最终从这些类型产生,而编译出哪种指令集的包,将由Architectures与Valid Architectures(因此这个不能为空)的交集来确定(Space-separated list of identifiers. Specifies the architectures for which the binary may be built. During the build, this list is intersected with the value of ARCHS build setting; the resulting list specifies the architectures the binary can run on. If the resulting architecture list is empty, the target generates no binary.)。

    Build Active Architecture Only

    指定是否只对当前连接设备所支持的指令集编译
    当其值设置为YES,这个属性设置为yes,是为了debug的时候编译速度更快,它只编译当前的architecture版本,而设置为no时,会编译所有的版本。 所以,一般debug的时候可以选择设置为yes,release的时候要改为no,以适应不同设备。

    二、工程配置,增加64位的支持

    note:在Xcode6.1.1及以上 Valid Architectures 设置里, 默认为 Standard architectures(armv7,arm64),如果你想改的话,自己在other中更改。

    使用 standard architectures (including 64-bit)(armv7,arm64) 参数,则打的包里面有32位、64位两份代码,在iPhone5s( iPhone5s的cpu是64位的 )下,会首选运行64位代码包, 其余的iPhone( 其余iPhone都是32位的,iPhone5c也是32位 ),只能运行32位包,但是包含两种架构的代码包,只有运行在ios6,ios7系统上。 这也就是说,这种打包方式,对手机几乎没要求,但是对系统有要求,即ios6以上。
    使用 standard architectures (armv7,armv7s) 参数, 则打的包里只有32位代码, iPhone5s的cpu是64位,但是可以兼容32位代码,即可以运行32位代码。但是这会降低iPhone5s的性能。 其余的iPhone对32位代码包更没问题, 而32位代码包,对系统也几乎也没什么限制。
    要发挥iPhone5s及以上的64位机型性能,就要包含64位包,那么系统最低要求为ios6。 如果要兼容ios5以及更低的系统,只能打32位的包,系统都能通用,但是会丧失iPhone5s的性能。

    举例:

    比如 Valid Architectures设置的支持arm指令集版本有:armv7/armv7s/arm64,对应的Architectures设置的支持arm指令集版本有:armv7s,这时Xcode只会生成一个armv7s指令集的二进制包。

    这里写图片描述

    注:如果你对ipa安装包大小有要求,可以减少安装包的指令集的数量,这样就可以尽可能的减少包的大小。

    制作静态库.a是指令集选择

    现在回归到正题,如何制作一个“没有问题”的.a静态库,通过以上信息了解到,当我们做App的时候,为了追求高效率,并且减小包的大小,Build Active Architecture Only设置成YES,Architectures按Xcode默认配置就可以,因为arm64向前兼容。但制作.a静态库就不同了,因为要保证兼容性,包括不同iOS设备以及模拟器运行不出错,所以结合当前行业情况,要做到最大的兼容性。
    ValidArchitectures设置为:armv7|armv7s|arm64|i386|x86_64
    Architectures设置不变(或根据你需要): armv7|arm64
    然后分别选择iOS设备和模拟器进行编译,最后找到相关的.a进行合包,使用lipo -create 真机库.a的路径 模拟器库.a的的路径 -output 合成库的名字.a ,这样就制作了一个通用的静态库.a。

    其它注意点:

    因此如果一些程序中使用的静态库不支持armv7s,而你的工程支持armv7s时,就会出现“xxxx does not contain a(n) armv7s slice:xxxxx for architecture armv7s”的编译错误,想要解决这个问题,有两个方法:
    如果是开源的,能够找到源代码,则可以用源代码重新打一个支持armv7s的libaray, 或者在工程中直接使用源代码,而不是静态库。
    如果不是开源的,要么就坐等第三方库的支持,要么就暂时让你的工程不支持armv7s。
    此外,模拟器并不运行arm代码,软件会被编译成x86可以运行的指令。所以生成静态库时都是会先生成两个.a,一个是i386的用于在模拟器运行,另一个是在真实设备上运行的,然后再用命令将两个.a合并成一个。
    需要注意的是iOS模拟器没有运行arm指令集,编译运行的是x86指令集,所以,只有在iOS设备上,才会执行设备对应的arm指令集。
    连接的手机指令集匹配是由高到低(arm64 > armv7s > armv7)依次匹配的。

    展开全文
  • iOS开发32位64位的坑

    2019-01-06 17:25:39
    众所周知,苹果是从iPhone 5s开始对全线移动产品使用64位架构,那么如果App需要兼容32位和64位的机型,就需要注意它们之间的区别。 下面我们首先看看基本数据类型的区别32位编译器 char :1个字节 char*(即...

    众所周知,苹果是从iPhone 5s开始对全线移动产品使用64位架构,那么如果App需要兼容32位和64位的机型,就需要注意它们之间的区别。

    下面我们首先看看基本数据类型的区别:

    32位编译器

    char :1个字节

    char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)

    short int : 2个字节

    int: 4个字节

    unsigned int : 4个字节

    float: 4个字节

    double: 8个字节

    long: 4个字节

    long long: 8个字节

    unsigned long: 4个字节

    64位编译器

    char :1个字节

    char*(即指针变量): 8个字节

    short int : 2个字节

    int: 4个字节

    unsigned int : 4个字节

    float: 4个字节

    double: 8个字节

    long: 8个字节

    long long: 8个字节

    从上面的比较我们可以看的出来,对于32位的机器来说,long是四个字节,而对于64位机器的long是8字节,如果在项目开发过程中忽略了这个点,很容易出现问题。下面举例分析:

    在我们的项目中,有这样的需求,服务器端返回一个时间戳,单位为毫秒,客户端需要解析该字段并转化为NSDate,存储到数据库中。对64位的机器我们只需要定义一个字段,比如startTime,类型为long,解析字段可以使用objectForKey的longValue获取到时间戳,然后转换为时间类型,没有任何问题。但是在32位,我们发现转换后的时间类型是错误的,类型1970...。究其原因,就是因为32位机器上毫秒级的时间戳longValue后越界,导致后续转换都异常。解决这类问题的方法是在涉及到时间戳为毫秒的情况下,定义相应字段是long long类型,通过longLongValue获取到值,就不存在溢出的情况。

    取值范围

    32bit下:

    unsigned int 0~4294967295
    int -2147483648~2147483647
    unsigned long 和int一样
    long 和int一样
    long long的最大值:9223372036854775807
    long long的最小值:-9223372036854775808
    unsigned long long的最大值:1844674407370955161
    __int64的最大值:9223372036854775807
    __int64的最小值:-9223372036854775808
    unsigned __int64的最大值:18446744073709551615

    64bit下

    unsigned int 0~4294967295
    int -2147483648~2147483647
    unsigned long 和 unsigned long long一样
    long 和long long一样
    long long的最大值:9223372036854775807
    long long的最小值:-9223372036854775808
    unsigned long long的最大值:1844674407370955161
    __int64的最大值:9223372036854775807
    __int64的最小值:-9223372036854775808
    unsigned __int64的最大值:18446744073709551615



    作者:以俊
    链接:https://www.jianshu.com/p/ffe964216134
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

     

     

    终究还是来了。Apple下发了支持64位的最后通牒:

    As we announced in October, beginning February 1, 2015 new iOS apps submitted to the App Store must include 64-bit support and be built with the iOS 8 SDK. Beginning June 1, 2015 app updates will also need to follow the same requirements.

    早应该做的适配终于要开始动工了,苦了64位的CPU运行了这么久32位的程序。前段时间公司项目完成了64-bit包的适配,本没那么复杂的事被无数不标准的老代码搅和的不轻,总结几个Tip共勉。

    Tips

    拒绝基本数据类型和隐式转换

    首当其冲的就是基本类型,比如下面4个类型在32-bit和64-bit下分别是多长呢?

    1

    2

    3

    4

    size_t s1 = sizeof(int);

    size_t s2 = sizeof(long);

    size_t s3 = sizeof(float);

    size_t s4 = sizeof(double);

    32-bit下:4, 4, 4, 8;64-bit下:4, 8, 4, 8

    (PS: 这个结果随编译器,换其他平台可不一定)

    它们的长度变化可能并非我们对64-bit长度加倍的预期,所以说,程序中出现sizeof的代码多看两眼。而且,除非你明确知道自己在做什么,应该使用下面的类型代替基本类型:

    • int -> NSInteger

    • unsigned -> NSUInteger

    • float -> CGFloat

    • 动画时间 -> NSTimeInterval

    这些都是SDK中定义的类型,而我们大部分时间都在跟SDK的API们打交道,使用它们能将类型转换的影响降低很多。

    再比如说下面的代码:

    1

    2

    3

    4

    NSArray *items = @[@1, @2, @3];

    for (int i = -1; i < items.count; i++) {

        NSLog(@"%d", i);

    }

    结果是,for循环一次都没有进。

    数组的count是NSUInteger类型的,-1与其比较时隐式转换成NSUInteger,变成了一个很大的数字:

    1

    2

    3

    4

    (lldb) p i

    (int) $0 = -1

    (lldb) p (NSUInteger)i

    (NSUInteger) $1 = 18446744073709551615

    这和64-bit到没啥关系,想要说明的是,这种隐式转换也需要小心,一定要注意和这个变量相关的所有操作(赋值、比较、转换)

    老式for循环可以考虑写成:

    1

    for (NSUInteger index = 0; index < items.count; index++) {}

    当然,数组遍历还是更推荐用for-in或block版本的,它们之间的比较可以回顾下这篇文章。

    使用新版枚举

    和上面的原因差不多,枚举应该使用新版的写法:

    1

    2

    3

    4

    5

    6

    typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {

        UIViewAnimationCurveEaseInOut,

        UIViewAnimationCurveEaseIn,

        UIViewAnimationCurveEaseOut,

        UIViewAnimationCurveLinear

    };

    不仅能为枚举值指定类型,而且当赋值赋错类型时,编译器还会给出警告,没理由不用这种写法。

    替代Format字符串

    适配64-bit时,你是否遇到了下面的恶心写法:

    1

    2

    NSArray *items = @[@1, @2, @3];

    NSLog(@"数组元素个数:%lu", (unsigned long)items.count);

    一般情况下,利用NSNumber的@语法糖就可以解决:

    1

    2

    NSArray *items = @[@1, @2, @3];

    NSLog(@"数组元素个数:%@", @(items.count));

    同理,int转string也可以:

    1

    2

    NSInteger i = 10086;

    NSString *string = @(i).stringValue;

    当然,如需要%.2f这种Format就不适用了。

    64-bit下的BOOL

    32-bit下,BOOL被定义为signed char,@encode(BOOL)的结果是'c'

    64-bit下,BOOL被定义为bool,@encode(BOOL)结果是'B'

    更直观的解释是:

    1

    2

    3

    4

    (lldb) p/t (signed char)7

    (BOOL) $0 = 0b00000111 (YES)

    (lldb) p/t (bool)7

    (bool) $1 = 0b00000001 (YES)

    32-bit版本的BOOL包括了256个值的可能性,还会引起一些坑,像这篇文章所说的。而64-bit下只有0(NO),1(YES)两种可能,终于给BOOL正了名。

    不直接取isa指针

    编译器已经默认禁用了这种使用,isa指针在32位下是Class的地址,但在64位下利用bits mask才能取出来真正的地址,若真需要,使用runtime的object_getClass 和object_setClass方法。关于64位下isa的讲解可以看这篇文章

    解决第三方lib依赖和lipo命令

    以源码形式出现在工程中的第三方lib,只要把target加上arm64编译就好了。

    恶心的就是直接拖进工程的那些静态库(.a)或者framework,就需要重新找支持64-bit的包了。这时候就能看出哪些是已无人维护的lib了,是时候找个替代品了(比如我全网找不到工程中用到的一个音频库的64位包,终于在一个哥们的github上找到,哭着给了个star- -)

    打印Mach-O文件支持的架构

    如何看一个可执行文件是不是支持64-bit呢?

    使用lipo -info命令,比如看看UIKit支持的架构:

    1

    2

    3

    // 当前在Xcode Frameworks目录

    sunnyxx$ lipo -info UIKit.framework/UIKit

    Architectures in the fat file: UIKit.framework/UIKit are: arm64 armv7s

    想看的更详细的信息可以使用lipo -detailed_info:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    sunnyxx$ lipo -detailed_info UIKit.framework/UIKit 

    Fat header in: UIKit.framework/UIKit

    fat_magic 0xcafebabe

    nfat_arch 2

    architecture arm64

        cputype CPU_TYPE_ARM64

        cpusubtype CPU_SUBTYPE_ARM64_ALL

        offset 4096

        size 16822272

        align 2^12 (4096)

    architecture armv7s

        cputype CPU_TYPE_ARM

        cpusubtype CPU_SUBTYPE_ARM_V7S

        offset 16826368

        size 14499840

        align 2^12 (4096)

    当然,还可以使用file命令:

    1

    2

    3

    4

    sunnyxx$ file UIKit.framework/UIKit 

    UIKit.framework/UIKit: Mach-O universal binary with 2 architectures

    UIKit.framework/UIKit (for architecture arm64):Mach-O 64-bit dynamically linked shared library

    UIKit.framework/UIKit (for architecture armv7s):Mach-O dynamically linked shared library arm

    上述命令对Mach-O文件适用,静态库.a文件,framework中的.a文件,自己app的可执行文件都可以打印下看看。

    合并多个架构的包

    如果,我们有MyLib-32.a和MyLib-64.a,可以使用lipo -create命令合并:

    1

    sunnyxx$ lipo -create MyLib-32.a MyLib-64.a -output MyLib.a

    支持64-bit后程序包会变大么?

    会,支持64-bit后,多了一个arm64架构,理论上每个架构一套指令,但相比原来会大多少还不好说,我们这里增加了大概50%,还有听说会增加一倍的。

    一个lib包含了很多的架构,会打到最后的包里么?

    不会,如果lib中有armv7, armv7s, arm64, i386架构,而target architecture选择了armv7s, arm64,那么只会从lib中link指定的这两个架构的二进制代码,其他架构下的代码不会link到最终可执行文件中;反过来,一个lib需要在模拟器环境中正常link,也得包含i386架构的指令。

    Checklist

    最后列一下官方文档中的注意点:

    • 不要将指针强转成整数

    • 程序各处使用统一的数据类型

    • 对不同类型的整数做运算时一定要注意

    • 需要定长变量时,使用如int32_t, int64_t这种定长类型

    • 使用malloc时,不要写死size

    • 使用能同时适配两个架构的格式化字符串

    • 注意函数和函数指针(类型转换和可变参数)

    • 不要直接访问Objective-C的指针(isa)

    • 使用内建的同步原语(Primitives)

    • 不要硬编码虚存页大小

    • Go Position Independent

    References

    https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40013501-CH1-SW1

    http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html

    http://www.bignerdranch.com/blog/64-bit-smorgasbord/

    http://www.bignerdranch.com/blog/bools-sharp-corners/

    展开全文
  • 苹果在2014年10月20号发布了一条消息:从明年的月一号开始,提交到App Store的应用必须支持64-bit。详细消息地址为:https://developer.apple.com/news/?id=10202014a那们我们应该如何开始着手让自己的App支持64-...

    苹果在2014年10月20号发布了一条消息:从明年的二月一号开始,提交到App Store的应用必须支持64-bit。详细消息地址为:https://developer.apple.com/news/?id=10202014a

    那们我们应该如何开始着手让自己的App支持64-Bit呢?

    基本知识

    从iPhone 5S的A7 CPU开始到刚刚发布的iPhone 6(A8 CPU)都已经支持64-bit ARM 架构。关于64-bit的介绍详见维基百科。知乎上有很多关于苹果使用A7,A8芯片的讨论,可以参考 iPhone 6 的 Apple A8 芯片对比 Apple A7 提升明显吗?, iPhone 5s 配备的 A7 处理器是 64 位,意味着什么?

    Xcode 5.0.1开始支持编译32-bit和64-bit的Binary
    同时支持32-bit和64-bit,我们需要选择的minimum deployment target为 iOS 5.1.1
    64-bit的Binary必须运行在支持64-bit的CPU上,并且最小的OS版本要求是 7.0.3
    关于Xcode “Build Setting”中的Architectures参数问题

    Architectures:你想支持的指令集。(支持指令集是通过编译生成对应的二进制数据包实现的,如果支持的指令集数目有多个,就会编译出包含多个指令集代码的数据包,造成最终编译的包很大。)
    Valid architectures:即将编译的指令集。(Valid architectures 和 Architecture两个集合的交集为最终编译生成的版本)
    Build Active Architecture Only:是否只编译当前设备适用的指令集(如果这个参数设为YES,使用iPhone 6调试,那么最终生成的一个支持ARM64指令集的Binary。一般在DEBUG模式下设为YES,RELEASE设为NO)
    关于指令集如下参考:

    ARMv8/ARM64: iPhone 6(Plus), iPhone 5s, iPad Air(2), Retina iPad Mini(2,3)
    ARMv7s: iPhone 5, iPhone 5c, iPad 4
    ARMv7: iPhone 3GS, iPhone 4, iPhone 4S, iPod 3G/4G/5G, iPad, iPad 2, iPad 3, iPad Mini
    ARMv6: iPhone, iPhone 3G, iPod 1G/2G
    对于支持64-bit,我们可以设置Architectures为 Standard architectures,在最新的Xcode 6上,它包括 armv7和arm64。

    让App支持32-bit和64-bit基本步骤

    确保Xcode版本号>=5.0.1
    更新project settings, minimum deployment target >= 5.1.1
    改变Architectures为 Standard architectures(include 64-bit)
    运行测试代码,解决编译warnings and errors,对照本文档或者官方文档 64-Bit Transition Guide for Cocoa Touch对相应地方做出修改。(编译器不能告诉我们一切)
    在真实的64-bit机器上测试
    使用Instruments查看内存使用问题
    64-bit主要的变化

    64-bit运行时环境和32-bit运行时环境主要有以下两点的不同:

    数据类型的改变
    方法调用上的改变
    数据类型的改变

    整型数据类型的变化如下:

    关于字节对齐的概念可以参考如下链接:http://blog.csdn.net/21aspnet/article/details/6729724#comments

    浮点型类型的改变如下:

    数据类型的改变可能会为我们的程序带来这些影响:

    增加内存压力
    64-bit到32-bit数据之间的相互转化
    计算可能产生不同的结果
    当把一个值从大的数据类型拷贝到小的数据类型,数据可能被截断。(NSInteger -> int)
    方法调用上的改变

    基于32-bit的CPU和基于64-bit上的CPU有不同数量的寄存器,在方法调用上有不同的协议。因此32-bit和64-bit在汇编层级上是不同的。如果我们在程序中不使用汇编编程,调用协议很少会遇到。

    如何编写健壮的64-bit代码

    根据上述改变,官方文档 64-Bit Transition Guide for Cocoa Touch给出如下7步:

    不要将长整型long赋值给整型int (64-bit上会导致数据丢失)
    不要将指针类型pointer赋值给整型int (64-bit导致地址数据丢失)
    留意数值计算(掩码计算,无符号整数和有符号整数同时使用等)
    留意对齐方法带来的变化
    32-bit到64-bit之间数据转化(通过网络传递的用户数据,可能同时存在于32-bit和64-bit的环境下)
    重写汇编代码
    不要在可变参数方法和不可变参数方法之前进行强制转化
    在LLVM编译器中,枚举类型也可以定义枚举的大小。我们在使用中,指派枚举值到一个变量时,应该使用适当的数据类型。

    不要将指针类型pointer赋值给整型int

    int a = 5;
    int *c = &a;

    /* 32-bit下正常,64-bit下错误。最新的Xcode6.0编译提示警告:’Cast to int* for smaller integer type int’*/
    int d = (int )((int)c + 4);

    /* 正确, 指针可以直接增加*/
    int *d = c + 1;
    如果我们一定要把指针转化为整型,可以把上述代码改为:

    /* 32-bit和64-bit都正常。*/
    int d = (int )((uintptr_t)c + 4);
    查看uintptr_t定义为 typedef unsigned long uintptr_t;

    保持数据类型一致

    方法使用时,入参,出参和赋值都需要注意保持数据类型一致。在iOS App中尤其要注意以下几个类型的正确使用:

    long
    NSInteger
    CFIndex
    size_t
    在32-bit和64-bit下,fpos_t和off_t都是64 bits的数据大小,永远不要把它们指向int整型。

    long PerformCalculation(void);
    int c = PerformCalculation(); // 错误 64-bit上数据将被截取
    long y = PerformCalculation(); // 正确

    int PerformAnotherCalculation(int input);
    long i = LONG_MAX;
    int x = PerformCalculation(i); // 错误

    int ReturnMax()
    {
    return LONG_MAX; // 错误
    }
    Cocoa中常见的数据类型转化问题

    NSInteger : 在32-bit和64-bit下有分别的定义:

    if LP64 || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64

        typedef long NSInteger;
    #else
        typedef int NSInteger;
    #endif
    

    我们永远不应该假设NSInteger和int是一样大的,下面的例子在使用中就需要注意:

    使用NSNumber对象转化时
    使用NSCoder编解码的时候,如果在64-bit设备下对NSInteger编码,在32-bit设备下对NSInteger解码。解码时如果值的大小超过了32-bit,这个时候就会出现异常
    Famework中使用NSInteger定义的一些常量
    CGFloat: 和NSInteger一样有不同的定义

    typedef CGFLOAT_TYPE CGFloat;

    if defined(LP64) && LP64

    define CGFLOAT_TYPE double

    else

    define CGFLOAT_TYPE float

    endif

    下面给出错误示范:

    CGFloat value = 200.0;
    CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &value); //64-bit下出现错误

    CGFloat value = 200.0;
    CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &value); //正确
    整型数值计算问题

    关于C语言的符号位扩展可参考资料为:http://blog.163.com/shi_shun/blog/static/237078492010651063936/

    我们直接来看例子:

    int a = -2;

    unsigned int b = 1;
    
    long c = a + b;
    
    long long d = c;
    
    printf("%lld\n", d);
    

    问题:这段代码在32-bit下运行结果符合我们的预期,输出为 -1(0xffffffff)。在64-bit下运行结果为:4294967295 (0x00000000ffffffff)。

    原因:一个有符号的值和一个同样精度的无符号的值相加结果是无符号的。这个无符号的结果被转换到更高精度的数值上时采用零扩展。

    解决方案:把变量b换成长整型long

    创建数据结构时使用合适的数据大小

    C99提供了内置的数据类型保证了一致的数据大小,即使底层的硬件结构不同。在某些case下,我们知道数据是一个固定的大小或者一个特定的变量拥有一个有限的取值范围。这个时候,我们应该选择特定的类型以避免浪费内存。

    类型如下:

    永远不要使用malloc去为变量申请特定内存的大小,改为使用sizeof来获取变量或者结构体的大小。

    另外我们还需要注意修改格式化字符串来同时支持32-bit和64-bit。

    小心处理方法和方法指针

    int fixedFunction(int a, int b);
    int variadicFunction(int a, …);

    int main
    {
    int value2 = fixedFunction(5,5);
    int value1 = variadicFunction(5,5);
    }
    上述两个方法中,在32-bit下使用相同的指令读取参数的数据,但是在64-bit上,是使用完全不同的协议来编译的。

    如果在代码中传递方法指针,应该保证方法调用的协议是一致的。永远不要将一个可变参数的方法转化成固定参数的方法。

    int MyFunction(int a, int b, …);

    int (action)(int, int, int) = (int ()(int, int, int)) MyFunction;
    action(1,2,3); // 错误示范
    上述错误的写法,编译器是不会提示警告或者错误的,并且在模拟器中也不会暴露出问题来。在发布自己的App前,一定记得要使用真机去测试。

    总结

    在支持64-bit过程中,应该按照Apple文档中提供的7个步骤完整检查项目工程。如果工程中涉及到大量的C或者C++代码,在支持64-bit中要更加谨慎。

    展开全文
  • 当时就看见苹果官方资料宣布iOS7.x的SDK支持了64位的应用,而且内置的应用都已经是64位。  我记得自己刚刚接触电脑时还有16的系统,指针的寻址范围还是16的。当年用TurboC时,还要根据应用的大小选择是tiny...
  • 内存对齐看这里:... iOS32位和64位下,数据类型占用字节 32位编译器char :1个字节char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)shor...
  • iOS与安卓的区别

    2020-06-18 09:12:50
    IOS与安卓的区别: 两者运行机制不同: IOS采用的是沙盒运行机制 安卓采用的是虚拟机运行机制 两者后台制度不同: IOS中任何第方程序都不能在后台运行 安卓中任何程序都能在后台运行,直到没有内存才会关闭 两者...
  • iOS11后32位应用升级

    2018-01-10 10:47:29
    这很容易就让我们想到与最近苹果iOS11放弃支持32位应用的事件有关。确实我在平时开发的项目中也没怎么涉及这个问题,这次在升级应用支持64位的过程中还是遇到了些问题,所以在这里总结一下,也许还会有同行的朋友...
  • 应用进行arm64升级时的一些注意项
  • iOS开发,编译器,32位64位适配
1 2 3 4 5 ... 20
收藏数 15,750
精华内容 6,300
热门标签
关键字:

64位和32位区别 ios