ios中不一定需要c構(gòu)建協(xié)議。但是總體來說用c語言來說相對對數(shù)據(jù)處理友好方便一些咬腋,不像oc那樣笨重羹膳,畢竟c是做底層的。但是用了c處理有時候需要考慮內(nèi)存釋放問題根竿。話不多說陵像。湃缎。。
如果某些協(xié)議中只出現(xiàn)8位的數(shù)據(jù)蠢壹,這種是相對最好處理的嗓违。例如:
如下協(xié)議:
可以構(gòu)建:
typedef struct{
????uint8_t head;
? ? uint8_t data_1;
? ? uint8_t data_2;
? ? uint8_t place[2];
? ? uint8_t check;
? ? uint8_t tail;
}Test_struct;
對于這種類型的數(shù)據(jù)要轉(zhuǎn)成oc的NSdata對象可用
Test_struct struct_data_context;
NSData *data = [NSData dataWithBytes:&struct_data_context length:sizeof(Test_struct)];
那么NSdata轉(zhuǎn)該類型的結(jié)構(gòu)體可用
Test_struct test_struct_data ;
[data getBytes:&test_struct_data length:sizeof(Test_struct)];
是不是很簡單图贸?不用一個一個賦值了蹂季!
但是。疏日。偿洁。如果數(shù)據(jù)中存在16位數(shù)據(jù) (數(shù)據(jù)分高低8位)這種情況下需要注意一下幾點
1.數(shù)據(jù)大小端
2.結(jié)構(gòu)體對齊(
原則1、數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct或聯(lián)合union)的數(shù)據(jù)成員沟优,第一個數(shù)據(jù)成員放在offset為0的地方涕滋,以后每個數(shù)據(jù)成員存儲的起始位置要從該成員大小的整數(shù)倍開始(比如int在32位機為4字節(jié),則要從4的整數(shù)倍地址開始存儲)挠阁。
原則2宾肺、結(jié)構(gòu)體作為成員:如果一個結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開始存儲侵俗。(struct a里存有struct b锨用,b里有char,int隘谣,double等元素增拥,那b應(yīng)該從8的整數(shù)倍開始存儲。)
原則3寻歧、收尾工作:結(jié)構(gòu)體的總大小掌栅,也就是sizeof的結(jié)果,必須是其內(nèi)部最大成員的整數(shù)倍码泛,不足的要補齊猾封。
)詳細(xì)的后面會提到
例如:以下協(xié)議格式(小端)
我們可以這樣構(gòu)建結(jié)構(gòu)體,
typedef struct{????uint8_t head;? ? uint8_t data_1; ?
uint16_tdata;? ? uint8_t place[2];? ? uint8_t check;? ? uint8_t tail;}Test_struct;
注意刪除線弟晚。對于16位數(shù)據(jù)小端處理的數(shù)據(jù)忘衍,(上表第3第4字節(jié))ios 處理器arm架構(gòu) 默認(rèn)處理數(shù)據(jù)都是小端傳輸?shù)模?uint16_t 數(shù)據(jù)映射到數(shù)組里就是低8位在前,高8位在后 形如{低8位卿城,高8位 } 的數(shù)組,到這里大家是不是覺得很簡單铅搓。NO NO NO瑟押,too ?? 了。星掰。多望。嫩舟。
莫急,我們可以測試打印的 sizeof (Test_struct)= 8怀偷;
下面比較下面的協(xié)議:
我們?nèi)绻凑丈厦孢壿嬑覀儠@樣構(gòu)建
typedef struct{????uint8_t head; ?uint16_t?data;? ? uint8_t place[2];? ? uint8_t check;? ? uint8_t tail;}Test_struct;
但是如果你打印一下 size 的話家厌,你會發(fā)現(xiàn)sizeof(Test_struct)還是等于 8;明明比上面少一位怎么還是8位椎工?
原因是 根據(jù)結(jié)構(gòu)體原則饭于。第二位成員2個字節(jié),第二位成員內(nèi)存從結(jié)構(gòu)體開始 2字節(jié)的倍數(shù)位開始排维蒙。所以 第一個成員占了第1字節(jié) 還有個補位第二個字節(jié)掰吕,uint16個低8位占了第三個字節(jié),?uint16個高8位占了第四個字節(jié)颅痊。加上后面的4個字節(jié)殖熟,一共8個字節(jié),第三原則(最大成員字節(jié)的整數(shù)陪)總字節(jié)數(shù)8的確是 最大成員2字節(jié)的整數(shù)倍斑响。
那這樣的話我們怎樣構(gòu)建結(jié)構(gòu)體方便些呢菱属?
1 。第一種把所有結(jié)構(gòu)體 改成一個字節(jié) 舰罚,意思是把uint16 高低字節(jié)拆開照皆。(常規(guī)做法)。
2沸停。結(jié)構(gòu)體補位
第一種就不用說了膜毁,我們試下第二種怎么做。
typedef struct{ uint8_t head;
uint8_t space; uint16_t data; uint8_t place[2]; uint8_t check; uint8_t tail; }Test_struct;
注意刪除線愤钾。我們在head 后面補了一位瘟滨。補了一位數(shù)據(jù)自然有出入,莫急能颁。我們最后生成的時候把這一位刪除數(shù)據(jù)就對了杂瘸。當(dāng)然方法有很多(數(shù)組遍歷賦值等等),我就用內(nèi)存拷貝補位前和補位后的內(nèi)存這種方法伙菊。
NSData * struct2NSdata(Test_struct *context) {
????????int temp_size = sizeof(Test_struct) - 1; //有效的數(shù)據(jù)字節(jié)數(shù)
????????uint8_t ?*temp_context = (uint8_t *)context; //強轉(zhuǎn)結(jié)構(gòu)體指針類型败玉,為了后面一個字節(jié)的偏移量
????????uint8_t *temp = malloc(temp_size);//分配內(nèi)存
????????memset(temp, 0, temp_size); //內(nèi)存塊初始化0
????????memcpy(temp, temp_context, 1);//拷貝第一位;
????????memcpy(temp + 1,temp_context + 2, temp_size - 1); //拷貝context第3位至結(jié)尾
????????NSData *result = [NSData dataWithBytes:temp length:temp_size]; //最終生成的data
????????free(temp); //釋放開辟的內(nèi)存
????????return result;
}
對于NSData 轉(zhuǎn)結(jié)構(gòu)體也是一個辦法補一位 哈哈
void nsdata2Struct(NSData *data , Test_struct *context) {
????????int temp_size = data.length; //有效的數(shù)據(jù)字節(jié)數(shù)
????????uint8_t *temp_context = context; //強轉(zhuǎn)結(jié)構(gòu)體
????????uint8_t *head_data = malloc(1);
????????[data getBytes:head_data range:NSMakeRange(0, 1)]; //儲存前內(nèi)存塊
? ? ? ? uint8_t *tail_data = malloc(temp_size - 1);
????????[data getBytes:head_data range:NSMakeRange(1, temp_size - 1)]; //儲存后面內(nèi)存塊
????????memcpy(temp_context, head_data, 1); //拷貝前內(nèi)存
????????memcpy(temp_context + 2, tail_data, data.length - 1); //拷貝后面的內(nèi)存塊 到第三字節(jié)至結(jié)尾 (忽略第二位)
????????free(head_data); //釋放
????????free(tail_data);
}
還有結(jié)構(gòu)體 第三原則 必須是最大成員的整數(shù)倍,如果不是會在結(jié)構(gòu)體最后一位補位镜硕。 處理方法也和上面類似运翼。
? 綜上,如果數(shù)據(jù)都是一個字節(jié)數(shù)據(jù)兴枯,構(gòu)建可以什么都不用考慮血淌,
?如果數(shù)據(jù)為小端傳輸,可以用上面方法,考慮一下結(jié)構(gòu)體對齊悠夯,不對齊需要補位癌淮,優(yōu)點是,數(shù)據(jù)轉(zhuǎn)換的時候不需要一個個賦值沦补,反正我是寫的手疼乳蓄。?
如果數(shù)據(jù)為大端傳輸,還是老老實實把成員都變成一個字節(jié)的成員變量夕膀,或者寫個函數(shù)高低位轉(zhuǎn)換虚倒。在用上面所提的方法。