php 大小端转换函数,数据大小端转换 按位运算 左移右移 iOS蓝牙通信数据处理...

目的

在蓝牙项目的开发过程中,会遇到了一些与数据处理有关的问题,本文对这些问题进行了基本的整理并分享给大家。包含如下三个方面的内容。数据大小端的介绍

大小端数据模式的转换

按位运算,左移、右移运算

一、数据大小端的介绍

网上关于数据大小端的介绍一大堆,为了让文章全面点,本文也就这方面简单说明一下。a. 大小端表示数据在计算机中的存放顺序。

b. 大端模式符合人类的正常思维,高字节保存在内存的低地址。

c. 小端模式方便计算机处理,高字节保存在内存的高地址。

d. iOS中默认的是小端存储。

424e158c4af956770049fd93baf921ea.png

大小端示意图

你可以在Xcode中运行下面这两行代码,就会打印出大小端模式。short int number = 0x8866;

NSLog(@"%@",[NSString stringWithFormat:@"%x",((char *)&number)[0]].intValue == 66 ? @"小端模式" : @"大端模式");

二、大小端数据模式的转换

在讲解iOS大小端转换之前,先来回忆回忆基本的数据计量单位。

1字节是一个8位的数据,可以代表从0-255共256个数字。

蓝牙每次发过来的数据通常是一个32位的数据(根据协议来自行定义),也就是4个字节。

1B(byte,字节)= 8 bit(位)。

蓝牙通信的时候,从硬件接收到的数据是NSData类型,我们需要对数据进行解析才能拿到真正方便使用的数据。

但是接收到的数据在内存中的保存顺序可能与我们希望的相反,所以在解析的过程中就涉及到了大小端的转换问题。

其实iOS的大小端转换非常方便,在苹果的Core Fundation中就提供了进行这些数据处理的方法。Apple官方文档

下面我就举几个例子,一起来看一下Fundation中与大小端有关方法的基本使用。

1、CFByteOrderGetCurrent()

返回当前电脑的大小端模式CFByteOrderGetCurrent()

返回的值是一个如下的枚举

enum __CFByteOrder {

CFByteOrderUnknown,       // 未知的

CFByteOrderLittleEndian,  // 小端模式

CFByteOrderBigEndian      // 大端模式

};

2、CFSwapInt16()

转换一个16位的整型数字// 把数字15转换模式

CFSwapInt16(15)

// 上面运算得到的结果十进制为3840,十六进制为0xF00。

// 而0xF00反转过来就是0xF = 15,所以证明这个方法确实对15进行了反转。

3、CFSwapInt16BigToHost()

把一个16位的整型数字从大端模式转为本机数据存放模式。如果本机为大端模式,则原值不变。// 把大端模式的数字Number转为本机数据存放模式

CFSwapInt16BigToHost(Number)

4、CFSwapInt32HostToBig()

把一个32位本机模式数据转换为大端模式。如果本机为大端模式,则原值不变。// 把本地存储模式的数字Number转为大端模式

CFSwapInt32HostToBig(Number)

还有好多方法(详见官方文档),基本都是大同小异,从字面就可以理解它的用法。

通常能用到的也就那么两三个。

一般需求是把大端转成本地模式,也就是小端模式。

CFSwapInt16BigToHost

CFSwapInt32BigToHost

下面是封装好了的两个方法,在开发中可以直接用来解析数据。

两个方法分别返回Signed和Unsigned类型的数据。

代码中的location代表准备解析的数据的位置,offset代表需要解析几位。需要注意的是,当仅仅是解析1位数据的时候,就不需要使用像CFSwapInt16BigToHost这样的方法了,具体可以查阅代码。// 转为本地大小端模式 返回Signed类型的数据

+(signed int)signedDataTointWithData:(NSData *)data Location:(NSInteger)location Offset:(NSInteger)offset {

signed int value=0;

NSData *intdata= [data subdataWithRange:NSMakeRange(location, offset)];

if (offset==2) {

value=CFSwapInt16BigToHost(*(int*)([intdata bytes]));

}

else if (offset==4) {

value = CFSwapInt32BigToHost(*(int*)([intdata bytes]));

}

else if (offset==1) {

signed char *bs = (signed char *)[[data subdataWithRange:NSMakeRange(location, 1) ] bytes];

value = *bs;

}

return value;

}// 转为本地大小端模式 返回Unsigned类型的数据

+(unsigned int)unsignedDataTointWithData:(NSData *)data Location:(NSInteger)location Offset:(NSInteger)offset {

unsigned int value=0;

NSData *intdata= [data subdataWithRange:NSMakeRange(location, offset)];

if (offset==2) {

value=CFSwapInt16BigToHost(*(int*)([intdata bytes]));

}

else if (offset==4) {

value = CFSwapInt32BigToHost(*(int*)([intdata bytes]));

}

else if (offset==1) {

unsigned char *bs = (unsigned char *)[[data subdataWithRange:NSMakeRange(location, 1) ] bytes];

value = *bs;

}

return value;

}

三、按位运算,左移、右移运算

当拿到了一个大小端转换完毕的数据,又会面临下一个问题,这个数据中不同的位可能代表了不同的意义(根据与硬件工程师的协议来定义),如何继续拿到对应位的数字呢?这时候,按位运算、左移右移就派上用场了。

1、按位与 &

同为1为1,否则为0

例如:3 & 5

0000 0011

0000 0101

0000 0001 = 1

所以 3 & 5=1

特点:

(1)清零:任何数和0相与,结果为0.

(2)取出指定位的值。取哪一位,就把对应的位定为1。

例如:

我们拿到一个16位的数据X,这个数据的低4位代表了版本号。

就可以利用按位与来拿到这个数字,代码如下// 0x0f的二进制为0000 1111,所以就取出了低4位的数据

int result = X & 0x0f;

2、按位或 |

只要有一个为1就为1

负数按补码的形式参加按位或运算

例如:3 | 5

0000 0011

0000 0101

0000 0111 = 7

所以 3 | 5=7

特点:

(1)对数据的某些位置1。

例如:

将X=1010 0000的后四位置1

1010 0000

0000 1111

1010 1111

这样后4位就全为1了

3、异或运算 ^

如果对应的位不同则为1,相同为0

例如 3 ^ 5

0000 0011

0000 0101

0000 0110

所以 3 ^ 5= 6

特点:

(1)特定位翻转,哪一位需要翻转就把对应的位设置为1

(2)任何数和0异或,原值不变。

(3)异或运算可以交换位置:3 ^ 5 ^ 6 == 3 ^ 6 ^ 5

(4)相同的数异或等于0:9 ^ 9 == 0

(5)a ^ b ^ a == b

4、取反 ~

0变1,1变0

例如 ~3

0000 0011

1111 1100

特点:

(1)配合按位与把一个数的最低位设置为0

例如:

把X=1011 0111按位与(~1)

X & (~1) = 1011 0110

这样最后一位就为0了

5、左移运算 <<

二进制位全部左移若干位,左边的丢弃,右边补0

例如 3<<2

0000 0011 = 3

0000 1100 = 12 (左移后)

左移3<<2 == 12

特点:

若左移时舍弃的最高位不包含1,则每左移一位,就乘以一次2.

所以a<

6、右移运算 >>

二进制右移若干位,正数左边补0,负数左边补1,右边丢弃。

例如 12>>2

0000 1100 = 12

0000 0011 = 2 (右移后)

右移12>>2 == 3

特点:

每右移一位,就除以一次2.

a>>n 就是 a除以2的n次方

例如:

继续用上面按位与的例子,

我们拿到一个16位的数据X,这次版本号不是低4位了,而是5-8位,该如何处理呢?

这种情况左移或右移就派上用场了。

代码如下// 0xf0的二进制为1111 0000,与X按位与之后,就取出了5-8位。

// 然后右移4位,最终得到了所需要的数据。

int result = (X & 0xf0) >> 4;

后记

蓝牙通信,数据处理是一个很重要的问题,实际开发过程中需要结合具体情境和协议来进行相关操作。

推荐简单又好用的分类集合:WHKit

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值