嵌入式C C 語言學習記錄1(非原創)

2021-09-19 11:50:30 字數 4809 閱讀 5937

3、c 和 c++間 struct 的深層區別

4、struct 程式設計注意事項

面對乙個人的大型 c/c++程式時,只看其對 struct 的使用情況我們就可以對其編寫者的程式設計經驗進行評估。因為乙個大型的 c/c++程式,勢必要涉及一些(甚至大量)進行資料組合的結構體,這些結構體可以將原本意義屬於乙個整體的資料組合在一起。從某種程度上來說,會不會用 struct,怎樣用struct,是區別乙個開發人員是否具備豐富開發經歷的標誌。

在網路協議、 通訊控制、 嵌入式系統的c/c++程式設計中, 我們經常要傳送的不是簡單的位元組流 (char型陣列),而是多種資料組合起來的乙個整體,其表現形式是乙個結構體。經驗不足的開發人員往往將所有需要傳送的內容依順序儲存在 char 型陣列中,通過指標偏移的方法傳送網路報文等資訊。這樣做程式設計複雜,易出錯,而且一旦控制方式及通訊協議有所變化,程式就要進行非常細緻的修改。乙個有經驗的開發者則靈活運用結構體。

舉乙個例子,假設網路或控制協議中需要傳送三種報文,其格式分別為 packeta、packetb、packetc:

struct structa

;struct structb

;struct structc

優秀的程式設計者這樣設計傳送的報文:

struct commupacket

};

在進行報文傳送時,直接傳送 struct commupacket 乙個整體

假設傳送函式的原形如下:

send(char * psenddata, unsigned int ilen);

傳送方可以直接進行如下呼叫,傳送 struct commupacket 的乙個例項

send( (char *)&sendcommupacket , sizeof(commupacket) );
假設接收函式的原形如下:

//返回值:實際接收到的位元組數

unsigned int recv(char * precvdata, unsigned int ilen);

接收方可以直接進行如下呼叫,將接收到的資料儲存在 struct commupacket 的乙個例項 recvcommupacket 中:

recv( (char *)&recvcommupacket , sizeof(commupacket) );
接著判斷報文型別進行相應處理:

switch(recvcommupacket. ipackettype)

以上程式中最值得注意的是

send( (char *)&sendcommupacket , sizeof(commupacket) );

recv( (char *)&recvcommupacket , sizeof(commupacket) );

中的強制型別轉換(char *)&sendcommupacket、(char *)&recvcommupacket先取位址,再轉化為 char 型指標,這樣就可以直接利用處理位元組流的函式。

利用這種強制型別轉化,我們還可以方便程式的編寫,例如要對 sendcommupacket 所處記憶體初始化為 0,可以這樣呼叫標準庫函式 memset():

memset((char *)&sendcommupacket,0, sizeof(commupacket));
intel、微軟等公司曾經出過一道類似的面試題:

#include #pragma pack(8)

struct example1

;struct example2

;#pragma pack()

int main(int argc, char* ar**)

問程式的輸入結果是什麼?

答案是:

8

164

不明白?還是不明白?下面一一道來:

struct 是一種復合資料型別,其構成元素既可以是基本資料型別(如 int、long、float 等)的變數,也可以是一些復合資料型別(如 array、struct、union 等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。

預設情況下,編譯器為結構體的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個結構的位址相同。

自然對界(natural alignment)即預設對齊方式,是指按結構體的成員中 size 最大的成員對齊。

例如:

struct naturalalign

;

在上述結構體中,size 最大的是 short,其長度為 2 位元組,因而結構體中的 char 成員 a、c 都以 2 為單位對齊,sizeof(naturalalign)的結果等於 6;

如果改為:

struct naturalalign

;

其結果顯然為 12。

一般地,可以通過下面的方法來改變預設的對界條件:

· 使用偽指令#pragma pack (n),編譯器將按照 n 個位元組對齊;

· 使用偽指令#pragma pack (),取消自定義位元組對齊方式。

注意: 如果#pragma pack (n)中指定的 n 大於結構體中最大成員的 size,則其不起作用,結構體仍然按照 size 最大的成員進行對界。

例如:

#pragma pack (n)

struct naturalalign

;#pragma pack ()

當 n 為 4、8、16 時,其對齊方式均一樣,sizeof(naturalalign)的結果都等於 12。而當 n 為 2時,其發揮了作用,使得sizeof(naturalalign)的結果為 6。

至此,我們可以對 intel、微軟的面試題進行全面的解答。

程式中第 2 行#pragma pack (8)雖然指定了對界為 8,但是由於 struct example1 中的成員最大size 為 4(long 變數 size 為 4),故 struct example1 仍然按 4 位元組對界,struct example1 的 size為 8,即第 18 行的輸出結果;

struct example2 中包含了 struct example1,其本身包含的簡單資料成員的最大 size 為 2 (short變數 e),但是因為其包含了 struct example1,而 struct example1 中的最大成員 size 為 4,struct example2 也應以 4 對界,#pragma pack (8)中指定的對界對 struct example2 也不起作用,故 19 行的輸出結果為 16;

由於 struct example2 中的成員以 4 為單位對界,故其 char 變數 c 後應補充 3 個空,其後才是成員 struct1 的記憶體空間,20 行的輸出結果為 4。

在 c++語言中 struct 具有了「類」 的功能,其與關鍵字 class 的區別在於 struct 中成員變數和函式的預設訪問許可權為 public,而 class 的為 private。

例如,定義 struct 類和 class 類:

struct structa

class classb

則:

structa a;

a.a = 'a'; //訪問 public 成員,合法

classb b;

b.a = 'a'; //訪問 private 成員,不合法

許多文獻寫到這裡就認為已經給出了 c++中 struct 和 class 的全部區別,實則不然,另外一點需要注意的是:

c++中的 struct 保持了對 c 中 struct 的全面相容(這符合 c++的初衷——「a better c」),因而,下面的操作是合法的:

//定義 struct

struct structa

;structa a = ; // 定義時直接賦初值

即 struct 可以在定義的時候直接以對其成員變數賦初值,而 class 則不能,在經典書目《thinking c++ 2nd edition》中作者對此點進行了強調。

看看下面的程式:

#include struct structa

; int main(int argc, char* ar**)

14 行的輸出結果是:a

16 行的輸出結果是:b

why?我們在 15 行對 instant2 的修改改變了 instant1 中成員的值!

原因在於 13 行的 instant2 = instant1 賦值語句採用的是變數逐個拷貝,這使得 instant1 和instant2 中的 cmember 指向了同一片記憶體,因而對 instant2 的修改也是對 instant1 的修改。

在 c 語言中,當結構體中存在指標型成員時,一定要注意在採用賦值語句時是否將 2 個例項中的指標型成員指向了同一片記憶體。

在 c++語言中,當結構體中存在指標型成員時,我們需要重寫 struct 的拷貝建構函式並進行「=」操作符過載。

嵌入式C語言學習(二)

c語音基礎 1.函式 形參與實參 函式呼叫 區域性變數和全域性變數 extern 動態儲存變數和靜態儲存變數 static 內部函式 定義加static 和外部函式 定義和使用時加extern 2.預編譯處理 2.1巨集定義 define 識別符號 字串 巨集名用大寫 巨集定義不是語句,不加分號 巨...

19 9 21 嵌入式C語言學習

準備再深入學習c語言為了更好的了解嵌入式程式設計 為後續的深入學習打下基礎,目前就自己感覺而言linux的學習不是走一條線,而是多線並進。c語言的學習的是必須掌握的,經常做題已經對裡面程式設計語法的熟悉 linux是作業系統的學習,了解其內部的執行原理,核心,以及一些命令的使用 要一直走在學習的路上...

嵌入式C語言 學習筆記

一 位運算 符號運算規則 與 兩個位都為1時,結果才為1 從真假方面看,只有當兩個位都為真時,結果才為真 或 兩個位都為0時,結果才為0 從真假方面看,如果兩個運算物件中相應的乙個位為真或者兩個位都為真,那麼結果為真 異或 兩個位相同為0,相異為1 從真假方面看,如果兩個運算物件中相應的乙個位為真且...