IOS 字符解析.

iOS 里涉及到C 語(yǔ)言的一些字節(jié)轉(zhuǎn)換記錄一下.
先看一段代碼,解析收到的 Data 里的 前6位 mac 地址

//解析收到的 Data 里的前6位 mac 地址
-(NSString *)getMAC:(NSData *)data{
//length 是個(gè) NSUInteger 型的數(shù)據(jù),表示的是 data 里字節(jié)的長(zhǎng)度.
    short len = (short)[data length];
//bytes 是個(gè)指針,指向 data 的內(nèi)容.char內(nèi)容
    Byte *_bytes  = (Byte *)[data bytes];
    //創(chuàng)建一個(gè)長(zhǎng)度為6的byte類型
    Byte *macData = malloc(6);
   //把 macData,0到6位初始化
    memset(macData, 0, 6);
   //開(kāi)始拷貝,把_bytes 里面的數(shù)據(jù)考到 macData 里. 從 (Len-6)位開(kāi)始拷貝.拷貝6位.加號(hào)代表從多少位開(kāi)始拷貝.
    memcpy(macData, _bytes + (len-6), 6);
//把字節(jié)數(shù)組轉(zhuǎn)換位 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 是個(gè) NSUInteger 型的數(shù)據(jù),表示的是 data 里字節(jié)的長(zhǎng)度.
    short len = (short)[data length];
//bytes 是個(gè)指針,指向 data 的內(nèi)容.char內(nèi)容
    Byte *_bytes  = (Byte *)[data bytes];

short len = (short)[data length];
NSData和它的可變長(zhǎng)子類 NSMutableData 是字節(jié)緩沖區(qū)的對(duì)象化封裝。我們可以獲得簡(jiǎn)單緩沖區(qū),并進(jìn)行一些轉(zhuǎn)換操作。通常我們并不會(huì)直接創(chuàng)建字節(jié)數(shù)據(jù),而是從其他類型的內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)據(jù)。所謂簡(jiǎn)單緩沖區(qū),就是緩沖區(qū)內(nèi)只包含數(shù)據(jù),無(wú)內(nèi)嵌指針。
簡(jiǎn)單來(lái)說(shuō),NSData 里放的是字節(jié)數(shù)據(jù).我們獲取到的是字節(jié)的長(zhǎng)度(char).

Byte *_bytes = (Byte *)[data bytes];
_ bytes 是個(gè)指針,指向 data 的內(nèi)容. 而 Byte 就 unsigned char 就是一個(gè)字節(jié)的長(zhǎng)度.
c++本身不存在BYTE關(guān)鍵字。但在C++中byte可以用unsigned char來(lái)表示,即無(wú)符號(hào)類型.
OC中對(duì) Byte 的定義:

typedef  UInt8                          Byte;
UInt8的定義:
typedef  unsigned char                  UInt8; //無(wú)符號(hào)的 char
typedef unsigned short                  UInt16;//無(wú)符號(hào)的 short
>>>有符號(hào)和無(wú)符號(hào)的區(qū)別
在內(nèi)存中,char與unsigned char沒(méi)有什么不同,都是一個(gè)字節(jié),唯一的區(qū)別是,char的最高位為符號(hào)位,因此char能表示-128~127, unsigned char沒(méi)有符號(hào)位,因此能表示0~255,這個(gè)好理解,8個(gè)bit,最多256種情況,因此無(wú)論如何都能表示256個(gè)數(shù)字。

NSMutabelData中l(wèi)ength與bytes的關(guān)系

short len = (short)[data length];
Byte *_bytes = (Byte *)[data bytes];
length 是個(gè) NSUInteger 型的數(shù)據(jù),表示的是 data 的長(zhǎng)度( data 里字節(jié)的長(zhǎng)度.), bytes 是個(gè)指針,指向 data 的內(nèi)容。不存在相等不相等,能不能相互替換的問(wèn)題。
@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.



 //創(chuàng)建一個(gè)長(zhǎng)度為6的byte類型
    Byte *macData = malloc(6);
   //把 macData,0到6位初始化
    memset(macData, 0, 6);
   //開(kāi)始拷貝,把_bytes 里面的數(shù)據(jù)考到 macData 里. 從 (Len-6)位開(kāi)始拷貝.拷貝6位.加號(hào)代表從多少位開(kāi)始拷貝.
    memcpy(macData, _bytes + (len-6), 6);
//把字節(jié)數(shù)組轉(zhuǎn)換位 NSData
    NSData  *mac =  [NSData dataWithBytes:macData length:6];

解析

這里規(guī)定,數(shù)據(jù) data 的最后6位是mac地址.所以在獲取到數(shù)據(jù)長(zhǎng)度后,取最后6個(gè)字節(jié),從 (Len-6)位開(kāi)始拷貝.拷貝6位.
通過(guò)NSData *mac = [NSData dataWithBytes:macData length:6];我們將獲取到的 char 還原成了 data

void* malloc(size_t size)
malloc 向系統(tǒng)申請(qǐng)分配指定size個(gè)字節(jié)的內(nèi)存空間。返回類型是 void* 類型。void* 表示未確定類型的指針。C,C++規(guī)定,void* 類型可以強(qiáng)制轉(zhuǎn)換為任何其它類型的指針。

memset()  
1.將已開(kāi)辟內(nèi)存空間 s 的首 n 個(gè)字節(jié)的值設(shè)為值 c。
2.memset() 函數(shù)常用于內(nèi)存空間初始化。如 char str[100]; memset(str,0,100);

void *memcpy(void *dest, const void *src, size_t n);
memcpy 函數(shù)用于 把資源內(nèi)存(src所指向的內(nèi)存區(qū)域) 拷貝到目標(biāo)內(nèi)存(dest所指向的內(nèi)存區(qū)域);拷貝多少個(gè)?有一個(gè)size變量控制

strcpy
C語(yǔ)言標(biāo)準(zhǔn)庫(kù)函數(shù)strcpy,把從src地址開(kāi)始且含有'\0'結(jié)束符的字符串復(fù)制到以dest開(kāi)始的地址空間
功能:把從src地址開(kāi)始且含有NULL結(jié)束符的字符串復(fù)制到以dest開(kāi)始的地址空間
說(shuō)明:src和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來(lái)容納src的字符串。
返回指向dest的指針

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

開(kāi)始拷貝
把_bytes 里面的數(shù)據(jù)考到 macData 里. 從 (Len-6)位開(kāi)始拷貝.拷貝6位.
加號(hào)代表從多少位開(kāi)始拷貝.



    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++;
        }
    }

解析

把每一個(gè)字節(jié)轉(zhuǎn)換成了16進(jìn)制.這樣獲取了 mac 地址

%02X X 表示以十六進(jìn)制形式輸出,02 表示不足兩位,前面補(bǔ)0輸出;出過(guò)兩位,不影響
舉例:
printf("%02X", 0x123); //打印出:123
printf("%02X", 0x1); //打印出:01



大小端轉(zhuǎn)換代碼

字節(jié)翻轉(zhuǎn).
//字節(jié)翻轉(zhuǎn)即:第一個(gè)和第四個(gè)交換,第二個(gè)和第三個(gè)交換
#include<Windows.h>
#include<stdio.h>
int main()
{
    BYTE byte_1,byte_2,byte_3,byte_4;
    unsigned int result;
    //value,int類型 占4個(gè)字節(jié),32位
    int value=306382034;//轉(zhuǎn)成16進(jìn)制就是0x12 43 04 d2
    byte_1=(value&0xff000000)>>24;
    byte_2=(value&0x00ff0000)>>16;
    byte_3=(value&0x0000ff00)>>8;
    byte_4=value&0x000000ff;
/*
拼裝字節(jié).
*/
    result=(byte_4<<24)+(byte_3<<16)+(byte_2<<8)+byte_1;
    return 0;
}


簡(jiǎn)單的寫法
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 ++;
    }
}

知識(shí)點(diǎn)

什么是大端/小端模式

  1. 在各種計(jì)算機(jī)體系結(jié)構(gòu)中,對(duì)于字節(jié)、字等的存儲(chǔ)機(jī)制有所不同,因而引發(fā)了計(jì)算機(jī)通信領(lǐng)域中一個(gè)很重要的問(wèn)題,即通信雙方交流的信息單元(比特、字節(jié)、字、雙字等等)應(yīng)該以什么樣的順序進(jìn)行傳送。如果不達(dá)成一致的規(guī)則,通信雙方將無(wú)法進(jìn)行正確的編/譯碼從而導(dǎo)致通信失敗。
    字節(jié)序,顧名思義字節(jié)的順序,再多說(shuō)兩句就是大于一個(gè)字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序(一個(gè)字節(jié)的數(shù)據(jù)當(dāng)然就無(wú)需談順序的問(wèn)題了)。
    1. 16位的處理器,一次能處理16bit的數(shù)據(jù)(2byte). 寄存器的寬度就是大于一個(gè)字節(jié).那么就要考慮如何存儲(chǔ)多字節(jié)的問(wèn)題.
      0x1122(2byte = 4個(gè)16進(jìn)制數(shù))
      0x11為高字節(jié), 0x22為低字節(jié)
      在內(nèi)存中,地址由小到大.內(nèi)存中的地址若為0x0010
      對(duì)于 大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,剛好相反。

    2. 32位的處理器一次能處理32bit的數(shù)據(jù)(2byte).
      0x1234 5678
      前面的0x1234 為高字節(jié) 0x5678為低字節(jié)
      而其中0x12位高字節(jié),34為低字節(jié)
      小端模式下,先存低字節(jié) 所以先存 0x5678.而0x5678中的低字節(jié)先存就是
      0x7856 同理另外一邊 0x3412
      結(jié)果就是0x7856 3412

這里有兩個(gè)概念,"內(nèi)存中的高地址和低地址","數(shù)據(jù)的高字節(jié)和低字節(jié)".

1. "內(nèi)存中的高地址和低地址",

高地址和低地址
在內(nèi)存中,地址由小到大.內(nèi)存中的地址
低地址 -----------------> 高地址

2. "數(shù)據(jù)的高字節(jié)和低字節(jié)".

如果我們有一個(gè)32位無(wú)符號(hào)整型0x12345678,那么高位是什么,低位又是什么呢?其實(shí)很簡(jiǎn)單。在十進(jìn)制中我們都說(shuō)靠左邊的是高位,靠右邊的是低位,在其他進(jìn)制也是如此。就拿 0x12345678來(lái)說(shuō),從高位到低位的字節(jié)依次是0x12、0x34、0x56和0x78。就是換成是二進(jìn)制數(shù)也是一樣的.
0x12345678:
高字節(jié) ————————> 低字節(jié)
0x12、0x34、0x56和0x78

  1. Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。
  2. Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端。
    舉一個(gè)例子,比如數(shù)字0x12 34 56 78在內(nèi)存中的表示形式為:
    1)大端模式:

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

低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
可見(jiàn),大端模式和字符串的存儲(chǔ)模式類似。

代碼解析

 //value(int類型,占4個(gè)字節(jié))
int value=306382034;//轉(zhuǎn)成16進(jìn)制就是0x12 43 04 d2
//獲取數(shù)據(jù)從高位到地位的每一個(gè)字節(jié).
byte_1=(value&0xff000000)>>24; 
byte_2=(value&0x00ff0000)>>16;
byte_3=(value&0x0000ff00)>>8;
byte_4=value&0x000000ff;

/*
拼裝字節(jié).
//第一個(gè)字節(jié)移動(dòng)到最后一個(gè)
//第二個(gè)字節(jié)移動(dòng)到第三個(gè)
//把第三個(gè)移動(dòng)到第二個(gè)
//把最后一個(gè)移動(dòng)到第一個(gè)
*/
    result=(byte_4<<24)+(byte_3<<16)+(byte_2<<8)+byte_1;

& 位運(yùn)算

計(jì)算的時(shí)候按位計(jì)算,&兩邊操作數(shù)對(duì)應(yīng)位上全為1時(shí),結(jié)果的該位值為1。否則該位值為0
例如:
0x12&0x23 轉(zhuǎn)為二進(jìn)制為:
B00010010&B00100011,
按位計(jì)算結(jié)果為B00000010,
即結(jié)果為0x02。

>>,<< 左右位移符號(hào)

把數(shù)字類型轉(zhuǎn)換為2進(jìn)制,>>2就是左移3位,缺位補(bǔ)零. <<2就是右移2位,也是缺位補(bǔ)零.
例如:14 >> 2 值等于3
因?yàn)?4(即二進(jìn)制的00001110)向右移兩位等于3(即二進(jìn)制的00000011)說(shuō)白了,就是把要移動(dòng)的數(shù)轉(zhuǎn)換成2進(jìn)制,右移幾位就去掉右邊的幾位數(shù),左移幾位就在右邊加幾個(gè)0
例如:14<<2的值為56

(value&0xff000000) 進(jìn)行&位運(yùn)算后,相當(dāng)于去掉后面24位.只保留1個(gè)字節(jié)(前8bit)
(value&0xff000000)>>24 把第一個(gè) byte 字節(jié),向后移動(dòng)24位.這樣我們就把第一個(gè)字節(jié)移動(dòng)到了最后一個(gè).獲取到了這個(gè)字節(jié).


總結(jié)

什么是數(shù)據(jù)類型?
使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量實(shí)際上就是一個(gè)指針,保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。

我們可能需要存儲(chǔ)各種數(shù)據(jù)類型(比如字符型、寬字符型、整型、浮點(diǎn)型、雙浮點(diǎn)型、布爾型等)的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么。

數(shù)據(jù)類型里存儲(chǔ)的都是數(shù)字.值的范圍根據(jù)類型的不同而不同.在進(jìn)行字節(jié)轉(zhuǎn)換的時(shí)候,要時(shí)刻抓住內(nèi)存,和字節(jié)的概念.做數(shù)據(jù)解析的時(shí)候,才不會(huì)亂.

字節(jié)數(shù)據(jù)

32位和64位 CPU 數(shù)據(jù)類型對(duì)比

image.jpeg

byte和 char

byte在java中才有的

char型是字符型,占2個(gè)字節(jié),默認(rèn)數(shù)值'\u0000',取值范圍'\u0000'~'\uffff'

byte是字節(jié)型,占1個(gè)字節(jié),默認(rèn)數(shù)值0,取值范圍-128~127

byte是屬于整數(shù)型的,其他整數(shù)型還有short(短整型)int(整形),long(長(zhǎng)整型)

uint8_t一般是指無(wú)符號(hào)8bit整型數(shù),其實(shí)就是unsigned char類型。C語(yǔ)言無(wú)此類型,需要自己定義,比如:

typedef unsigned char uint8_t;

于char類型只相差一個(gè)符號(hào),一般可以直接轉(zhuǎn)換:

char* a = (char*)b;

uint8_t* b = (uint8_t*)a;

uint8_t 無(wú)符號(hào)8bit整型數(shù)

int16_t 有符號(hào)16bit整形數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 文章圖片上傳不正常,如需文檔,可聯(lián)系微信:1017429387 目錄 1 安裝... 4 1.1 配置探針... ...
    Mrhappy_a7eb閱讀 6,447評(píng)論 0 5
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,010評(píng)論 2 89
  • 小說(shuō)看多了,就成了旁觀者 一個(gè)自以為看透世事的旁觀者 我并不冷漠,反而多情 小說(shuō)里有淚有笑 哭多半由于感動(dòng) 笑大約...
    一掬溫涼任平生閱讀 270評(píng)論 0 2
  • 今天是安裝上電腦的第一天,心情比較好,終于有了除手機(jī)之外的電子設(shè)備,可以在上面看電視學(xué)習(xí),看科目一得題目。每個(gè)人都...
    自卑又粘人的小妖精閱讀 141評(píng)論 0 0
  • 有許多話,不說(shuō)時(shí)人盡皆知,說(shuō)出來(lái)反倒顯得矯情。但今天是八一,我想借這個(gè)特殊的節(jié)日矯情一把。 不過(guò),我不談軍人,因?yàn)?..
    林陣閱讀 1,808評(píng)論 0 1