iOS藍牙通信數(shù)據(jù)處理,位運算绰筛,數(shù)據(jù)的大小端轉(zhuǎn)換

在藍牙項目的開發(fā)過程中枢泰,會遇到了一些與數(shù)據(jù)處理有關(guān)的問題

  1. 數(shù)據(jù)大小端的介紹
  2. 大小端數(shù)據(jù)模式的轉(zhuǎn)換
  3. 按位運算,左移铝噩、右移運算

?? AppStore:記錄Box

一衡蚂、數(shù)據(jù)大小端的介紹

a. 大小端表示數(shù)據(jù)在計算機中的存放順序。
b. 大端模式符合人類的正常思維骏庸,高字節(jié)保存在內(nèi)存的低地址毛甲。
c. 小端模式方便計算機處理,高字節(jié)保存在內(nèi)存的高地址具被。
d. iOS中默認(rèn)的是小端存儲玻募。

大小端示意圖.png

你可以在Xcode中運行下面這兩行代碼,就會打印出大小端模式一姿。

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

二补箍、大小端數(shù)據(jù)模式的轉(zhuǎn)換

藍牙通信的時候,從硬件接收到的數(shù)據(jù)是NSData類型啸蜜,我們需要對數(shù)據(jù)進行解析才能拿到真正方便使用的數(shù)據(jù)坑雅。
但是接收到的數(shù)據(jù)在內(nèi)存中的保存順序可能與我們希望的相反,所以在解析的過程中就涉及到了大小端的轉(zhuǎn)換問題衬横。

其實iOS的大小端轉(zhuǎn)換非常方便裹粤,在蘋果的Core Fundation中就提供了進行這些數(shù)據(jù)處理的方法。Apple官方文檔

下面我就舉幾個例子,一起來看一下Fundation中與大小端有關(guān)方法的基本使用遥诉。

1拇泣、CFByteOrderGetCurrent()
返回當(dāng)前電腦的大小端模式

CFByteOrderGetCurrent()
返回的值是一個如下的枚舉
enum __CFByteOrder {
    CFByteOrderUnknown,       // 未知的
    CFByteOrderLittleEndian,  // 小端模式
    CFByteOrderBigEndian      // 大端模式
};

2、CFSwapInt16()
轉(zhuǎn)換一個16位的整型數(shù)字

// 把數(shù)字15轉(zhuǎn)換模式
CFSwapInt16(15)

// 上面運算得到的結(jié)果十進制為3840矮锈,十六進制為0xF00霉翔。
// 而0xF00反轉(zhuǎn)過來就是0xF = 15,所以證明這個方法確實對15進行了反轉(zhuǎn)苞笨。

3债朵、CFSwapInt16BigToHost()
把一個16位的整型數(shù)字從大端模式轉(zhuǎn)為本機數(shù)據(jù)存放模式。如果本機為大端模式瀑凝,則原值不變序芦。

// 把大端模式的數(shù)字Number轉(zhuǎn)為本機數(shù)據(jù)存放模式
CFSwapInt16BigToHost(Number)

4、CFSwapInt32HostToBig()
把一個32位本機模式數(shù)據(jù)轉(zhuǎn)換為大端模式粤咪。如果本機為大端模式谚中,則原值不變。

// 把本地存儲模式的數(shù)字Number轉(zhuǎn)為大端模式
CFSwapInt32HostToBig(Number)

還有好多方法(詳見官方文檔)寥枝,基本都是大同小異宪塔,從字面就可以理解它的用法。

通常能用到的也就那么兩三個囊拜。
一般需求是把大端轉(zhuǎn)成本地模式蝌麸,也就是小端模式。

CFSwapInt16BigToHost
CFSwapInt32BigToHost

下面是封裝好了的兩個方法艾疟,在開發(fā)中可以直接用來解析數(shù)據(jù)。
兩個方法分別返回Signed和Unsigned類型的數(shù)據(jù)敢辩。
代碼中的location代表準(zhǔn)備解析的數(shù)據(jù)的位置蔽莱,offset代表需要解析幾位。

  • 需要注意的是戚长,當(dāng)僅僅是解析1位數(shù)據(jù)的時候盗冷,就不需要使用像CFSwapInt16BigToHost這樣的方法了,具體可以查閱代碼同廉。
// 轉(zhuǎn)為本地大小端模式 返回Signed類型的數(shù)據(jù)
+(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;
}
// 轉(zhuǎn)為本地大小端模式 返回Unsigned類型的數(shù)據(jù)
+(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;
}

三仪糖、按位運算,左移迫肖、右移運算

在講解位運算和左右移之前锅劝,先來回憶回憶基本的數(shù)據(jù)計量單位。

1字節(jié)是一個8位的數(shù)據(jù)蟆湖,可以代表從0-255共256個數(shù)字故爵。
1B(byte,字節(jié))= 8 bit(位)隅津。

模擬一次解析數(shù)據(jù)的過程:

  1. 假如藍牙每次發(fā)過來的數(shù)據(jù)大小為32個字節(jié)诬垂,這個數(shù)據(jù)在NSData類型下Log出來是這個樣子:<0aa60000 00000000 00000000 00000000 00000000 00000059 9db56800 00260b01>
  2. 每兩個數(shù)字表示一個十六進制的數(shù)據(jù)劲室,例如最左邊的0a代表了一個字節(jié),也就是0x0A = 10结窘。
  3. 現(xiàn)在我們要截取最左邊的0aa6這兩個字節(jié)(16位)很洋,這個數(shù)據(jù)是UInt16類型,那么首先要做的就是運用上面封裝好了的大小端轉(zhuǎn)換方法來截取這兩個字節(jié)隧枫,下面代碼中的result就是所需要的數(shù)據(jù)喉磁。
// 從第0位開始,截取2個字節(jié)悠垛,所以location是0线定,offset是2
UInt16 result = [self unsignedDataTointWithData:data Location:0 Offset:2];

可是拿到result之后工作還沒有結(jié)束。

  • 需求:result的二進制是0000 1010 1010 0110确买,一個16位的數(shù)字斤讥,假如與硬件工程師提前說好了,低4位(0110)代表組數(shù)湾趾,5-8位(1010)代表每組的人數(shù)芭商。
    如何分別拿出所需的數(shù)據(jù)呢?

這時候搀缠,位運算就派上用場了铛楣。
一起來看看位運算和左右移的基本使用方法和情景,需求的答案也在其中艺普。

1簸州、按位與 &

同為1為1,否則為0

例如:3 & 5
0000 0011
0000 0101
0000 0001 = 1
所以 3 & 5=1

特點:
(1)清零:任何數(shù)和0相與歧譬,結(jié)果為0.
(2)取出指定位的值岸浑。取哪一位,就把對應(yīng)的位定為1瑰步。

例如:
拿到了一個16位的數(shù)據(jù)result = 0000 1010 1010 0110矢洲,如何拿到這個數(shù)據(jù)的低4位呢?
就可以使用按位與缩焦,代碼如下

// 0x000f == 0000 0000 0000 1111
// 按位與上result之后读虏,得到的number == 0000 0000 0000 0110 就是低4位的數(shù)據(jù)0110
int number = result & 0x000f;

2、按位或 |

只要有一個為1就為1
負數(shù)按補碼的形式參加按位或運算

例如:3 | 5
0000 0011
0000 0101
0000 0111 = 7
所以 3 | 5=7

特點:
(1)對數(shù)據(jù)的某些位置1袁滥。

例如:
將X=1010 0000的后四位置1
1010 0000
0000 1111
1010 1111
這樣后4位就全為1了

3盖桥、異或運算 ^

如果對應(yīng)的位不同則為1,相同為0

例如 3 ^ 5
0000 0011
0000 0101
0000 0110
所以 3 ^ 5= 6

特點:
(1)特定位翻轉(zhuǎn)题翻,哪一位需要翻轉(zhuǎn)就把對應(yīng)的位設(shè)置為1
(2)任何數(shù)和0異或葱轩,原值不變。
(3)異或運算可以交換位置:3 ^ 5 ^ 6 == 3 ^ 6 ^ 5
(4)相同的數(shù)異或等于0:9 ^ 9 == 0
(5)a ^ b ^ a == b

4、取反 ~

0變1靴拱,1變0

例如 ~3
0000 0011
1111 1100

特點:
(1)配合按位與把一個數(shù)的最低位設(shè)置為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<<n 就是 a乘以2的n次方

6偎窘、右移運算 >>

二進制右移若干位乌助,正數(shù)左邊補0,負數(shù)左邊補1陌知,右邊丟棄他托。

例如 12>>2
0000 1100 = 12
0000 0011 = 2 (右移后)
右移12>>2 == 3

特點:
每右移一位,就除以一次2.
a>>n 就是 a除以2的n次方

例如:
繼續(xù)用上面按位與的例子仆葡,
拿到了一個16位的數(shù)據(jù)result = 0000 1010 1010 0110赏参,如何拿到這個數(shù)據(jù)的5-8位呢?
首先運用按位與把5-8位之外的數(shù)據(jù)全部置0沿盅,然后用右移來拿到具體數(shù)值把篓。
代碼如下

// 0x00f0 == 0000 0000 1111 0000,result按位與0xf0之后腰涧,結(jié)果為0000 0000 1010 0000
// 然后右移4位韧掩,得到最終所需要的數(shù)據(jù)number == 0000 0000 0000 1010
int number = (result & 0x00f0) >> 4;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市窖铡,隨后出現(xiàn)的幾起案子疗锐,更是在濱河造成了極大的恐慌,老刑警劉巖费彼,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滑臊,死亡現(xiàn)場離奇詭異,居然都是意外死亡敌买,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門阶界,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虹钮,“玉大人,你說我怎么就攤上這事膘融≤搅唬” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵氧映,是天一觀的道長春畔。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么律姨? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任振峻,我火速辦了婚禮,結(jié)果婚禮上择份,老公的妹妹穿的比我還像新娘扣孟。我一直安慰自己,他們只是感情好荣赶,可當(dāng)我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布凤价。 她就那樣靜靜地躺著,像睡著了一般拔创。 火紅的嫁衣襯著肌膚如雪利诺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天剩燥,我揣著相機與錄音慢逾,去河邊找鬼。 笑死躏吊,一個胖子當(dāng)著我的面吹牛氛改,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播比伏,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胜卤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赁项?” 一聲冷哼從身側(cè)響起葛躏,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悠菜,沒想到半個月后舰攒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡悔醋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年摩窃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芬骄。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡猾愿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出账阻,到底是詐尸還是另有隱情蒂秘,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布淘太,位于F島的核電站姻僧,受9級特大地震影響鞠苟,放射性物質(zhì)發(fā)生泄漏害驹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望震叙。 院中可真熱鬧犬金,春花似錦散怖、人聲如沸俐芯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缓升。三九已至,卻和暖如春蕴轨,著一層夾襖步出監(jiān)牢的瞬間港谊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工橙弱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留歧寺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓棘脐,卻偏偏與公主長得像斜筐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛀缝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,974評論 2 355

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

  • Objective-C語言中有各種各樣的運算符可處理數(shù)字中的特定位顷链,如下表所示: 符號運算 & 按位與| 按位...
    笙笙哥閱讀 669評論 0 0
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,975評論 6 13
  • 1 關(guān)鍵字 1.1 關(guān)鍵字的概述 Java的關(guān)鍵字對java的編譯器有特殊的意義,他們用來表示一種數(shù)據(jù)類型屈梁,或...
    哈哈哎呦喂閱讀 655評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理嗤练,服務(wù)發(fā)現(xiàn),斷路器在讶,智...
    卡卡羅2017閱讀 134,658評論 18 139
  • 導(dǎo)讀:“18歲女孩同吃兩種感冒藥后離奇死亡”的“新聞”爆紅網(wǎng)絡(luò)构哺,讓許多人膽戰(zhàn)心驚革答。 去年年底,一則“18歲女孩同吃...
    嵐逸筠篁閱讀 795評論 0 2