IOS 字符解析.

iOS 里涉及到C 语言的一些字节转换记录一下.
先看一段代码,解析收到的 Data 里的 前6位 mac 地址

//解析收到的 Data 里的前6位 mac 地址
-(NSString *)getMAC:(NSData *)data{
//length 是个 NSUInteger 型的数据,表示的是 data 里字节的长度.
    short len = (short)[data length];
//bytes 是个指针,指向 data 的内容.char内容
    Byte *_bytes  = (Byte *)[data bytes];
    //创建一个长度为6的byte类型
    Byte *macData = malloc(6);
   //把 macData,0到6位初始化
    memset(macData, 0, 6);
   //开始拷贝,把_bytes 里面的数据考到 macData 里. 从 (Len-6)位开始拷贝.拷贝6位.加号代表从多少位开始拷贝.
    memcpy(macData, _bytes + (len-6), 6);
//把字节数组转换位 NSData
    NSData  *mac =  [NSData dataWithBytes:macData length:6];

    NSString *ret = nil;

    if(mac != nil){

        int index = 0;

        while (index < 6) {

            if (ret != nil){

                ret = [NSString stringWithFormat:@"%@:",ret];

            }

            if (ret == nil) {

                ret = [NSString stringWithFormat:@"%02x", macData[index]];

            }else {

                ret =[NSString stringWithFormat:@"%@%02x",ret, macData[index]];

            }
            index++;
        }
    }
    free(macData);

    return ret;

}

代码分析

-(NSString *)getMAC:(NSData *)data{
//length 是个 NSUInteger 型的数据,表示的是 data 里字节的长度.
    short len = (short)[data length];
//bytes 是个指针,指向 data 的内容.char内容
    Byte *_bytes  = (Byte *)[data bytes];

short len = (short)[data length];
NSData和它的可变长子类 NSMutableData 是字节缓冲区的对象化封装。我们可以获得简单缓冲区,并进行一些转换操作。通常我们并不会直接创建字节数据,而是从其他类型的内容转换成字节数据。所谓简单缓冲区,就是缓冲区内只包含数据,无内嵌指针。
简单来说,NSData 里放的是字节数据.我们获取到的是字节的长度(char).

Byte *_bytes = (Byte *)[data bytes];
_ bytes 是个指针,指向 data 的内容. 而 Byte 就 unsigned char 就是一个字节的长度.
c++本身不存在BYTE关键字。但在C++中byte可以用unsigned char来表示,即无符号类型.
OC中对 Byte 的定义:

typedef  UInt8                          Byte;
UInt8的定义:
typedef  unsigned char                  UInt8; //无符号的 char
typedef unsigned short                  UInt16;//无符号的 short
>>>有符号和无符号的区别
在内存中,char与unsigned char没有什么不同,都是一个字节,唯一的区别是,char的最高位为符号位,因此char能表示-128~127, unsigned char没有符号位,因此能表示0~255,这个好理解,8个bit,最多256种情况,因此无论如何都能表示256个数字。

NSMutabelData中length与bytes的关系

short len = (short)[data length];
Byte *_bytes = (Byte *)[data bytes];
length 是个 NSUInteger 型的数据,表示的是 data 的长度( data 里字节的长度.), bytes 是个指针,指向 data 的内容。不存在相等不相等,能不能相互替换的问题。
@property(readonly) NSUInteger length
The number of bytes contained by the data object.
@property(readonly) const void *bytes
A pointer to the receiver’s contents.



 //创建一个长度为6的byte类型
    Byte *macData = malloc(6);
   //把 macData,0到6位初始化
    memset(macData, 0, 6);
   //开始拷贝,把_bytes 里面的数据考到 macData 里. 从 (Len-6)位开始拷贝.拷贝6位.加号代表从多少位开始拷贝.
    memcpy(macData, _bytes + (len-6), 6);
//把字节数组转换位 NSData
    NSData  *mac =  [NSData dataWithBytes:macData length:6];

解析

这里规定,数据 data 的最后6位是mac地址.所以在获取到数据长度后,取最后6个字节,从 (Len-6)位开始拷贝.拷贝6位.
通过NSData *mac = [NSData dataWithBytes:macData length:6];我们将获取到的 char 还原成了 data

void* malloc(size_t size)
malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。

memset()  
1.将已开辟内存空间 s 的首 n 个字节的值设为值 c。
2.memset() 函数常用于内存空间初始化。如 char str[100]; memset(str,0,100);

void *memcpy(void *dest, const void *src, size_t n);
memcpy 函数用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);拷贝多少个?有一个size变量控制

strcpy
C语言标准库函数strcpy,把从src地址开始且含有'\0'结束符的字符串复制到以dest开始的地址空间
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针

memcpy(macData, _bytes + (len-6), 6);

开始拷贝
把_bytes 里面的数据考到 macData 里. 从 (Len-6)位开始拷贝.拷贝6位.
加号代表从多少位开始拷贝.



    NSString *ret = nil;
//mac 可以判断是不是有值,避免空值的情况.
    if(mac != nil){

        int index = 0;

        while (index < 6) {

            if (ret != nil){

                ret = [NSString stringWithFormat:@"%@:",ret];

            }

            if (ret == nil) {

                ret = [NSString stringWithFormat:@"%02x", macData[index]];

            }else {

                ret =[NSString stringWithFormat:@"%@%02x",ret, macData[index]];

            }
            index++;
        }
    }

解析

把每一个字节转换成了16进制.这样获取了 mac 地址

%02X X 表示以十六进制形式输出,02 表示不足两位,前面补0输出;出过两位,不影响
举例:
printf("%02X", 0x123); //打印出:123
printf("%02X", 0x1); //打印出:01



大小端转换代码

字节翻转.
//字节翻转即:第一个和第四个交换,第二个和第三个交换
#include<Windows.h>
#include<stdio.h>
int main()
{
    BYTE byte_1,byte_2,byte_3,byte_4;
    unsigned int result;
    //value,int类型 占4个字节,32位
    int value=306382034;//转成16进制就是0x12 43 04 d2
    byte_1=(value&0xff000000)>>24;
    byte_2=(value&0x00ff0000)>>16;
    byte_3=(value&0x0000ff00)>>8;
    byte_4=value&0x000000ff;
/*
拼装字节.
*/
    result=(byte_4<<24)+(byte_3<<16)+(byte_2<<8)+byte_1;
    return 0;
}


简单的写法
void convertToLittleEndian(unsigned int *data, int len)
{
    for (int index = 0; index < len; index ++) {
        
        *data = ((*data & 0xff000000) >> 24)
        | ((*data & 0x00ff0000) >>  8)
        | ((*data & 0x0000ff00) <<  8)
        | ((*data & 0x000000ff) << 24);
        
        data ++;
    }
}

知识点

什么是大端/小端模式

  1. 在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编/译码从而导致通信失败。
    字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。
    1. 16位的处理器,一次能处理16bit的数据(2byte). 寄存器的宽度就是大于一个字节.那么就要考虑如何存储多字节的问题.
      0x1122(2byte = 4个16进制数)
      0x11为高字节, 0x22为低字节
      在内存中,地址由小到大.内存中的地址若为0x0010
      对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。

    2. 32位的处理器一次能处理32bit的数据(2byte).
      0x1234 5678
      前面的0x1234 为高字节 0x5678为低字节
      而其中0x12位高字节,34为低字节
      小端模式下,先存低字节 所以先存 0x5678.而0x5678中的低字节先存就是
      0x7856 同理另外一边 0x3412
      结果就是0x7856 3412

这里有两个概念,"内存中的高地址和低地址","数据的高字节和低字节".

1. "内存中的高地址和低地址",

高地址和低地址
在内存中,地址由小到大.内存中的地址
低地址 -----------------> 高地址

2. "数据的高字节和低字节".

如果我们有一个32位无符号整型0x12345678,那么高位是什么,低位又是什么呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x12345678来说,从高位到低位的字节依次是0x12、0x34、0x56和0x78。就是换成是二进制数也是一样的.
0x12345678:
高字节 ————————> 低字节
0x12、0x34、0x56和0x78

  1. Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
  2. Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
    举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
    1)大端模式:

低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:

低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
可见,大端模式和字符串的存储模式类似。

代码解析

 //value(int类型,占4个字节)
int value=306382034;//转成16进制就是0x12 43 04 d2
//获取数据从高位到地位的每一个字节.
byte_1=(value&0xff000000)>>24; 
byte_2=(value&0x00ff0000)>>16;
byte_3=(value&0x0000ff00)>>8;
byte_4=value&0x000000ff;

/*
拼装字节.
//第一个字节移动到最后一个
//第二个字节移动到第三个
//把第三个移动到第二个
//把最后一个移动到第一个
*/
    result=(byte_4<<24)+(byte_3<<16)+(byte_2<<8)+byte_1;

& 位运算

计算的时候按位计算,&两边操作数对应位上全为1时,结果的该位值为1。否则该位值为0
例如:
0x12&0x23 转为二进制为:
B00010010&B00100011,
按位计算结果为B00000010,
即结果为0x02。

>>,<< 左右位移符号

把数字类型转换为2进制,>>2就是左移3位,缺位补零. <<2就是右移2位,也是缺位补零.
例如:14 >> 2 值等于3
因为14(即二进制的00001110)向右移两位等于3(即二进制的00000011)说白了,就是把要移动的数转换成2进制,右移几位就去掉右边的几位数,左移几位就在右边加几个0
例如:14<<2的值为56

(value&0xff000000) 进行&位运算后,相当于去掉后面24位.只保留1个字节(前8bit)
(value&0xff000000)>>24 把第一个 byte 字节,向后移动24位.这样我们就把第一个字节移动到了最后一个.获取到了这个字节.


总结

什么是数据类型?
使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量实际上就是一个指针,保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。

我们可能需要存储各种数据类型(比如字符型、宽字符型、整型、浮点型、双浮点型、布尔型等)的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么。

数据类型里存储的都是数字.值的范围根据类型的不同而不同.在进行字节转换的时候,要时刻抓住内存,和字节的概念.做数据解析的时候,才不会乱.

字节数据

32位和64位 CPU 数据类型对比

image.jpeg

byte和 char

byte在java中才有的

char型是字符型,占2个字节,默认数值'\u0000',取值范围'\u0000'~'\uffff'

byte是字节型,占1个字节,默认数值0,取值范围-128~127

byte是属于整数型的,其他整数型还有short(短整型)int(整形),long(长整型)

uint8_t一般是指无符号8bit整型数,其实就是unsigned char类型。C语言无此类型,需要自己定义,比如:

typedef unsigned char uint8_t;

于char类型只相差一个符号,一般可以直接转换:

char* a = (char*)b;

uint8_t* b = (uint8_t*)a;

uint8_t 无符号8bit整型数

int16_t 有符号16bit整形数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容

  • 文章图片上传不正常,如需文档,可联系微信:1017429387 目录 1 安装... 4 1.1 配置探针... ...
    Mrhappy_a7eb阅读 6,175评论 0 5
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,805评论 2 89
  • 小说看多了,就成了旁观者 一个自以为看透世事的旁观者 我并不冷漠,反而多情 小说里有泪有笑 哭多半由于感动 笑大约...
    一掬温凉任平生阅读 245评论 0 2
  • 今天是安装上电脑的第一天,心情比较好,终于有了除手机之外的电子设备,可以在上面看电视学习,看科目一得题目。每个人都...
    自卑又粘人的小妖精阅读 122评论 0 0
  • 有许多话,不说时人尽皆知,说出来反倒显得矫情。但今天是八一,我想借这个特殊的节日矫情一把。 不过,我不谈军人,因为...
    林阵阅读 1,700评论 0 1