iphone arm32 & base64 基础数据类型疑问
事情如下:
/*
long a1 =145463470;
long a2 = 33;
long a3 = a1*a2;
*/
---------------------------
一般处理,都没太多想法,可Iphone出了新版本架构 64位的 iphone 5s,6,6s
/*
32Bit - 505327214
64Bit - 4800294510
*/
------------------------------------------------------
于是想着可能是 double 在不同的cpu指令架构下,有不同的字节长度.于是继续实验.
1 -(void) typeSizeBit 2 { 3 unsigned char uint8 = 0; 4 signed char int8 = 0; 5 unsigned short uint16 = 0; 6 signed short int16 = 0; 7 unsigned int uint32 = 0; 8 signed int int32 = 0; 9 float fp32 = 0; 10 double fp64 = 0; 11 unsigned long ulong = 0; 12 long llong = 0; 13 int iint = 0; 14 15 printf("unsigned char is %d bit\n\r", sizeof(uint8)*8); 16 printf("signed char is %d bit\n\r", sizeof(int8)*8); 17 printf("unsigned short is %d bit\n\r", sizeof(uint16)*8); 18 printf("signed short is %d bit\n\r", sizeof(int16)*8); 19 printf("unsigned int is %d bit\n\r", sizeof(uint32)*8); 20 printf("signed int is %d bit\n\r", sizeof(int32)*8); 21 printf("float fp32 is %d bit\n\r", sizeof(fp32)*8); 22 printf("double fp64 is %d bit\n\r", sizeof(fp64)*8); 23 printf("unsigned long is %d bit\n\r", sizeof(ulong)*8); 24 printf("long is %d bit\n\r", sizeof(llong)*8); 25 printf("int is %d bit\n\r", sizeof(iint)*8); 26 27 }
日志输出如下:
/*
iphone5 arm7 32位cpu指令集架构
---------------------------
-- unsigned char is 8 bit
-- signed char is 8 bit
-- unsigned short is 16 bit
-- signed short is 16 bit
-- unsigned int is 32 bit
-- signed int is 32 bit
-- float fp32 is 32 bit
-- double fp64 is 64 bit
-- unsigned long is 32 bit
---------------------------
iphone6 arm64 64指令集架构
---------------------------
-- unsigned char is 8 bit
-- signed char is 8 bit
-- unsigned short is 16 bit
-- signed short is 16 bit
-- unsigned int is 32 bit
-- signed int is 32 bit
-- float fp32 is 32 bit
-- double fp64 is 64 bit
-- unsigned long is 64 bit
---------------------------
*/
---------------------------
可见long类型在不同的cpu指令集架构下,位数不一样。
但问题是,为什么 double类型在 32位系统下面,数值反而减小了呢?
这是个问题,暂时还没搞清楚原因-
截止时间 2015.10.28 13:19
--------------------------- --------------------------- --------------------------- --------------------------- ---------------------------
10.29 11:06
昨天的问题想了挺久,翻了不少文章,其中翻到一遍讲 64位计算程序注意点说明 的文章,文中提到了【在32位系统中long和int的长度是一样的,不过在64位系统中就有可能出问题,因为64位系统中long比int长,将long值赋予int将导致数据丢失。】,顿时让我觉得肯定是 long类型在32位与64位的字节长度问题,引起的溢出,才导致结果不一样。
于是我开始做实验,过程如下:
1 -(void)long64BitTest 2 { 3 uint64_t a1 =145463470; 4 uint64_t a2 = 33; 5 uint64_t a3 = a1*a2; 6 7 return; 8 }
---------iphone5 arm7 32位 输出结果-------------
---------------------------
-- uint64_t a3 = 4800294510
---------------------------
---------iphone6 base64 64位 输出结果-------------
---------------------------
-- uint64_t a3 = 4800294510
---------------------------
果然,终于结果是一致的了,其中 uint64_t 定义为: typedef unsigned long long uint64_t; 共 8个字结长度,共 64位,最大值: 1.84467440737096E19
适用于大数据的计算。
而 我们再看一组对比:
1 -(void)long32BitTest 2 { 3 long a1 =145463470; 4 long a2 = 33; 5 uint64_t a3 = a1*a2; 6 7 return; 8 }
---------iphone5 arm7 32位 输出结果-------------
---------------------------
-- uint64_t a3 = 505327214
---------------------------
---------iphone6 base64 64位 输出结果-------------
---------------------------
-- uint64_t a3 = 4800294510
---------------------------
其结果也出人意料,即然知道a1*a2 出来的结果是大数据,只能用 64位类型定义,但为什么出来的结果却不是正确的 4800294510。
原因是这样的, a1与a2是Long型,在 32位系统下面,long型最大值为 4294967296. 而a1*a2 单独运算后,才会赋值给 a3. 而a1*a2在 32位的Long下面,已经溢出为505327214,
其结果可想而知了。
综合上述,为了移植的正确性,我们在进行大数据运算的时候,可以定为 long long类型,这样就能保证定义的变量为 64位长度值。
然后,我实验了一下android系统下面,long值为 64位,没有无符号类型,最大值为 1.84467440737096E19 ,基本能满足运算的要求。
++++++++++++++++++++++++++++++++++
IOS版本 ---> 自定义哈希函数
-------------------------------------------------------------
1 -(int) hashCode:(NSString*) tmpStr 2 { 3 double 4 int hash = 0; 5 6 int i=0; 7 8 9 const char *chatlist = [tmpStr UTF8String]; 10 int ad=33; 11 for (i=0; i<tmpStr.length; ++i) { 12 13 int adhash = ad*hash; 14 hash = adhash + chatlist[i]; 15 //printf("%c - %d -%d - %d\n",chatlist[i],chatlist[i],hash,adhash); 16 } 17 18 19 if (hash<0) { 20 hash = -1 * hash; 21 } 22 23 return hash; 24 } 25 26 - (void)viewDidLoad { 27 [super viewDidLoad]; 28 // Do any additional setup after loading the view, typically from a nib. 29 30 //[self hashCode]; 31 32 NSArray *arStringList = @[@"wuxian",@"无线天下",@"temobi长778844Ok",@"234xxxxxxxxxxxxxxxxxxxx324234234234234234"]; 33 for (NSString *str in arStringList) { 34 NSLog(@"%d,", [self hashCode:str]); 35 } 36 37 return; 38 }
++++++++++++++++++++++++++++++++++
Android版本 ----->
-------------------------------------------------------------
1 /** 2 * @param 哈希值 3 * @return 4 */ 5 public static int bernstein(String key) { 6 int hash = 0; 7 int i; 8 for (i = 0; i < key.length(); ++i) 9 hash = 33 * hash + key.charAt(i); 10 return hash; 11 } 12 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 17 //typeSizeBit(); 18 String[] array=new String[4]; 19 array[0]="wuxian"; 20 array[1]="无线天下"; 21 array[2]="temobi长778844Ok四"; 22 array[3]="234xxxxxxxxxxxxxxxxxxxx324234234234234234"; 23 24 25 for(int i=0;i<array.length;i++){ 26 int tempCode = bernstein(array[i]); 27 Log.e("info", String.format("%d",tempCode) ); 28 } 29 30 }
通过实验,修改后的,统一 自定义哈希code 函数如下:
+++++++++++++IOS版本+++++++++++++++++++++++
1 -(int) hashCode:(NSString*) tmpStr 2 { 3 4 int i = 0; 5 int ad = 33; 6 int hash = 0; 7 8 for (i=0; i<tmpStr.length; ++i) { 9 int adhash = ad*hash; 10 unichar cAT = [tmpStr characterAtIndex:i]; 11 hash = adhash + cAT; 12 } 13 14 if (hash<0) { 15 hash *= -1; 16 } 17 18 return hash; 19 }
-------> 测试代码
1 NSArray *arStringList = @[@"wuxian",@"无线天下",@"temobi长778844Ok四",@"234xxxxxxxxxxxxxxxxxxxx324234234234234234"]; 2 for (NSString *str in arStringList) { 3 NSLog(@"%d,", [self hashCode:str]); 4 }
+++++++++++++Android版本+++++++++++++++++++++
1 public static int bernstein(String key) { 2 int hash = 0; 3 int i; 4 for (i = 0; i < key.length(); ++i) 5 { 6 hash = 33 * hash + key.charAt(i); 7 } 8 9 if(hash<0) hash *= -1; 10 11 return hash; 12 }
-------> 测试代码
1 public void onCreate(Bundle savedInstanceState) 2 { 3 String[] array=new String[4]; 4 array[0]="wuxian"; 5 array[1]="无线天下"; 6 array[2]="temobi长778844Ok四"; 7 array[3]="234xxxxxxxxxxxxxxxxxxxx324234234234234234"; 8 9 for(int i=0;i<array.length;i++) 10 { 11 int tempCode = bernstein1(array[i]); 12 Log.e("GallaryTest", String.format("%d",tempCode) ); 13 } 14 }
++++++++++++++++++++++++++++++++++
输出结果值如下:
505327324,
973344947,
1438764634,
1926919377
++++++++++++++++++++++++++++++++++
转载介绍64位说明文章 [http://blog.csdn.net/fhbystudy/article/details/12752967]
随着iPhone5S的推出,大家开始关心5S上所使用的64位CPU A7。
除了关心A7的性能以外,大家还会关心一个问题,那就是使用A7的64位系统对应用有没有什么要求。特别是应用开发者,大家都比较关心我们的应用如 何迁移到 64位的系统上来,以充分发挥A7的能力。其实这些问题都可以在苹果的官方文档《64-Bit transition Guide for Cocoa Touch》中找到答案。
为了方便大家,我将《64-Bit transition Guide for Cocoa Touch》中的一些重点整理了一下,希望可以为大家节约一些详细阅读文档的时间,如果我理解有不对的地方请大家指正。
首先,A7使用的是ARM V8架构,除了使用64位的地址总线和64位的寄存器以外,还增加了寄存器的数量,目前A7中的整数和浮点数寄存器是A6的两倍。
这里需要强调的是,寄存器的增加大大提高了程序的运行速度。将CPU由32位提高到64位,最主要的改变增大了寻址能力,可以突破32位系统只能访 问3G内存的限制(32位系统在理论上可以访问4G内存,因为2的32次方约等于4 290 000 000,很多32位系统只能访问3G左右的内存是因为有一大部分地址被分配给I/O系统了,所以总体可用内存就不足4G了),但是,32位到64位的改变 并不一定意味着程序运行速度的提高,甚至有些情况下会因为64位系统中的数据占用内存变大而导致程序运行速度变慢。而寄存器数量的增加,则直接提高了程 序运行速度,当然,前提是你的应用需要重新为64位系统编译一遍,让程序可以充分使用所有的寄存器。
使用Xcode 5可以很方便地将以前的应用编译成64位程序,基本过程如下:
- 1. 使用Xcode 5 打开原有项目。
- 2. 将支持的设备改成“iOS 7”。
- 3. 在“Build Setting”中将“Architectures”改成“Standard Architectures (including 64-bit)”。
- 4. 运行测试程序,解决编译过程出现的问题。
其中第4步是关键,具体会遇到什么问题和原来程序的设计有关,包括使用数据类型的方式是否标准等,后面会继续讨论细节,其实《64-Bit transition Guide for Cocoa Touch》一书主要就是讲这些细节。
在讨论细节之前有一些较为宏观的内容大家可以了解一下。
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将跑得更快。真的是“大家好才是真的好”。
后面我们来看看一些为64位系统调整程序的技术细节。
32位的iOS系统和64位的iOS系统主要的差别有两个,一个是数据类型的差别,一个是过程调用方法的差别。
在数据类型上,主要的变化是指针类型(Pointer)和长整数类型(long)的长度变化和内存对齐方式的变化,同时也导致了更高级别数据类型的变化,如NSInteger的长度也有变化。
在过程调用方法上,因为ARM V8 和ARM V7具有不同数量的寄存器,具有不同的过程调用约定,所以32位系统和64位系统在汇编层级是不同的。
根据以上两方面的变化,书中总结了以下要点,开发人员根据以下要点来检查原来的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位系统对于这两种过程调用方式的处理方法不同。
按以上几个重点去检查程序就差不多了,当然,具体的细节还有很多,需要在实际工作中结合代码和调试结果进行分析。
总之,建议具体负责应用迁移的开发者需要完整阅读《64-Bit transition Guide for Cocoa Touch》。