美文网首页
byte <==> int 转换

byte <==> int 转换

作者: 环宇飞杨 | 来源:发表于2020-05-17 16:37 被阅读0次

先看两段代码

int 转换 byte

- (NSData *)makeSendData
{
    Byte serviceByteData[1] = {};
    
    serviceByteData[0] =(Byte)((self.head.service & 0x000000FF));
    
    Byte groupByteData[1] = {};
    
    groupByteData[0] =(Byte)((self.head.group & 0x000000FF));
    
    Byte typeByteData[2] = {};
    
    typeByteData[0] =(Byte)((self.head.type & 0x0000FF00)>>8);
    
    typeByteData[1] =(Byte)((self.head.type & 0x000000FF));
    
    Byte lengthByteData[4] = {};
    
    lengthByteData[0] =(Byte)((self.head.bodyLength & 0xFF000000)>>24);
    
    lengthByteData[1] =(Byte)((self.head.bodyLength & 0x00FF0000)>>16);
    
    lengthByteData[2] =(Byte)((self.head.bodyLength & 0x0000FF00)>>8);
    
    lengthByteData[3] =(Byte)((self.head.bodyLength & 0x000000FF));

    Byte byte[] = {serviceByteData[0],groupByteData[0],typeByteData[0],typeByteData[1],lengthByteData[0],lengthByteData[1],lengthByteData[2],lengthByteData[3]};
    NSData *temphead = [[NSData alloc]initWithBytes:byte length:8];
    
    NSMutableData *m_data = [[NSMutableData alloc] init];
    [m_data appendData:temphead];
    GPBMessage *message = self.body;
    [m_data appendData:message.data];
    //不打印心跳
    if (self.head.service == 1 && self.head.type == CMDType_CtrClientHeartbeat) {
//        NSLog(@"++++++++++++++++++TCP发送心跳");
        return m_data;
    }
    if (self.head.service == 2 && self.head.type == MessageTypeCode_MessageTypeSyncConn) {
        return m_data;
    }
    
    if (self.head.service == CMDService_IM || self.head.service == CMDService_common) {
        return m_data;
    }
    
#if DEBUG
    NSLog(@"TCP发送消息\nhead:%@, \nbody:%@",self.head,self.body);
#endif
    return m_data;
}

byte 转int

- (BOOL)parseHeadWithData:(NSData *)data
    {
        if (data.length != 8) {
            return NO;
        }
        
        Byte serviceLengthBytes[1];
        [data getBytes:serviceLengthBytes range:NSMakeRange(0, 1)];
        
        self.messageData.head.service = (int)  ((serviceLengthBytes[0]&0xff));
        
        Byte groupLengthBytes[1];
        [data getBytes:groupLengthBytes range:NSMakeRange(1, 1)];
        
        self.messageData.head.group = (int)  ((groupLengthBytes[0]&0xff));
        
        Byte typeLengthBytes[2];
        [data getBytes:typeLengthBytes range:NSMakeRange(2, 2)];
        
        self.messageData.head.type = ((typeLengthBytes[0]&0xff)| ((typeLengthBytes[1] << 8)&0xff00));
        
        Byte bodyLengthBytes[4];
        [data getBytes:bodyLengthBytes range:NSMakeRange(4, 4)];
        
        self.messageData.head.bodyLength = ((bodyLengthBytes[0]&0xff) | ((bodyLengthBytes[1] << 8)&0xff00) | ((bodyLengthBytes[2] << 16)&0xff0000) | ((bodyLengthBytes[3] << 24)&0xff000000));
        
        if (checkCPUendian() == 1) {
            self.messageData.head.type = ntohs(self.messageData.head.type);//小端转大端
        }
        
        if (checkCPUendian() == 1) {
            self.messageData.head.bodyLength = ntohl(self.messageData.head.bodyLength);//小端转大端
        }
        return YES;
    }

因项目里用到socket ,需要按位去读取报文信息,报头总共8个字节,其中

  1. server 占一个字节
  2. group 占一个字节
  3. type 占两个字节
  4. bodyLength 占四个字节

以上代码就是是约定的报头解析和组装部分。

组装

占用一个字段的就先略过了,不需要移位,直接使用即可。

type 字段占用两个字节

typeByteData[0] =(Byte)((self.head.type & 0x0000FF00)>>8);
typeByteData[1] =(Byte)((self.head.type & 0x000000FF));

一个字节占8位二进制,相当于两位16进制,所以type占两个字节的话,那么最大值就是 0x0000FFFF。
其中第一个字节typeByteData[0],和0x0000FF00 按位与 就相当于只保留前两位16进制的值,其它全清零,然后再右移8位就等于把右侧零全部消除,然后就得到了type字段代表的16进制的高位。

其余逻辑类似。

解析

Byte typeLengthBytes[2];
[data getBytes:typeLengthBytes range:NSMakeRange(2, 2)];
self.messageData.head.type = ((typeLengthBytes[0]&0xff)| ((typeLengthBytes[1] << 8)&0xff00));

其中 (typeLengthBytes[0]&0xff) 部分 ,因为typeLengthBytes[0]就代表低位,所以 &0xff基本也没什么意义,关键的typeLengthBytes[1] << 8 就等于将高位的值左移8位,再将右侧的8位清零, 此处的&0xff00 其实也没什么意义,所以可以简写为

self.messageData.head.type = ((typeLengthBytes[0])| (typeLengthBytes[1] << 8));

中间的|,按位或,意义等于将两位拼接,
比如 typeLengthBytes[1] = 1111000100000000, typeLengthBytes[0] = 0000000011101010.
拼接后就等于 1111000111101010,此时的值就代表两个字节的type字段。

其余逻辑类似。

大端小端

首先大小端的定义是啥?为什么会有大小端之分?

一串二进制流,最终要对应到计算机的内存中去计算,那么赋值时是按内存的从低到高,还是从高到低就有不一样的实现,本无性能优劣之分,只是两种实现而已

借两张图


小端模式.jpg
大端模式.jpg

大小端判断

int checkCPU()
{
    union w
    {
        int a;//在ios中,4 Byte
        char b;//在ios中,1 Byte
    } c;
    c.a = 1;
    return(c.b ==1);//如果c.b == 1,表示第一位是0x01,那就是小端,如果返回0,就是大端
}

其原理主要使用union 类型来判断,其中union类型叫做共用体,一般用于编译期的内存优化,特性就是内部数据共享一个内存地址。所以如果给c.a赋值为1,那么去读b的值得时候,如果可以读到刚才设置的1 ,考虑a和b占用的字节数不一样,那么说明这个1被保存在了低位(参考上图1),那就是小端模式(),反之,那就是大端模式。

iOS中判断大小端的标准写法

if (NSHostByteOrder() == NS_LittleEndian) {
        NSLog(@"LittleEndian");
}
else if(NSHostByteOrder() == NS_BigEndian){
         NSLog(@"BigEndian");
}
else {
         NSLog(@"Unknow");
}

因为服务端的默认为大端模式,所以iOS的小端需要稍微转换下,函数为:

ntohs(x)//两字节专用
ntohl(x) //四字节专用

完。

相关文章

网友评论

      本文标题:byte <==> int 转换

      本文链接:https://www.haomeiwen.com/subject/sjhsohtx.html