嵌入式C語言深入篇之 變數

2021-10-24 15:36:20 字數 2745 閱讀 7718

新建乙個物聯網行業交流學習qq群,感興趣可加:928840648

*****cut*****

可執行程式儲存區

當乙個c/c++原碼檔案被編譯鏈(比如gcc/g++)編譯及鏈結成為可執行程式後,由4個段組成,分別是:**段,資料段,棧,堆。

**段(.text)包含**邏輯(函式),以及巨集定義(#define)常量。

資料段包含3部分:.bss

,.rodata,.data。

.bss: block started by symbol,存放程式中未初始化的全域性變數。

.rodata:read only data,用於存放不可變修改的常量資料。

.data:靜態變數和已初始化的全域性變數儲存區。

棧(.stack)主要用來存放區域性變數, 傳遞的引數, 存放函式的返回位址;程式執行過程中動態生成及**,不需要使用者**儲存空間。

堆(.heap)由malloc等api動態分配的記憶體區域,其生命週期由free決定;程式執行過程中動態生成,需要由使用者自行**。

了解程式的組成儲存區有利於開發過程中對程式的精簡,比如我們可以選擇變數內容及大小是直接編譯進可執行程式(rom)中,還是程式執行過程中才被例項化(ram);如果**量10w+行基本能很明顯的出現差異,同樣功能有的**編譯出來占用空間非常大,有的很精簡,其中乙個原因就是對底層儲存分割槽的理解不同。

在我們ubuntu server目錄:~/workspace/basics/c/3_2_variables,存放著本章節我們會用到的源**檔案;其中main_1.c的內容是針對變數/函式的分割槽儲存結構做了描述:

我們嘗試保留及注釋掉.data裡面的乙個儲存空間,對比兩者編譯後程式的大小。

差別巨大:

動態型別

本節內容原始碼在:~/workspace/basics/c/3_2_variables/main_2.c中,主要講解c語言中的動態型別變數定義的方法,需要使用到的關鍵字是:typeof()

,該關鍵字是gnu c提供的一種特性,可以用來取得變數/函式的型別,或者表示式的型別。常用的方式如下:

取得變數型別。

定義乙個變數,可以是普通變數也可以是指標變數,然後typeof取得該變數型別並用於定義另外同型別的變數;比如圖中所示的value。

取得函式型別做函式指標。

主要用來取得函式的型別,並定義函式指標使用,圖中所示的指標func就是取著函式add型別定義的。

取得表示式型別做處理。

取得表示式相對較為複雜,圖中所示,我們將函式add的運算結果匯出來用於判斷;該技巧同樣可以用於函式呼叫失敗後的多次重試。

編譯執行如下:

​​​​​​​型別轉換

在c語言中,進行型別之間的轉換有兩種轉換方式:隱式型別轉換 和 強制型別轉換。其中強制型別轉換是由開發人員完成的,比如float val = (float)u8;

一般不會出現問題,所以我們重點關心隱式型別轉換。

隱式型別轉換是由編譯器主動完成的,如果由低型別到高型別的隱式型別轉換是安全的,不會發生截斷;相反由高型別到低型別的隱式型別轉換是不安全的,會發生截斷產生不正確的結果:

四種情況下會發生隱式型別轉換:賦值,算術運算,函式傳參,函式返回值。

在原始碼檔案:main_3.c中,我們列出了四種情況的例子:

賦值。

圖中我們定義的型別uint8_t u8,並賦值為250;同時定義int8_t i8,然後把u8賦值給i8,顯然這個過程出現型別不匹配的轉換,由於250已經超過i8的最大範圍,因此i8不在是數值250了。

算術運算。

兩個uint8_t型別相加,賦值給uint16_t,實際上編譯器在執行該條指令時,會把兩個uint8_t先轉換為uint16_t,所以圖中:

uint16_t both = cal_1 + cal_2; 等價於:

uint16_t both = (uint16_t)cal_1 + (uint16_t)cal_2;

隱式型別轉換後資料正確。

函式傳參。

函式add的引數型別都是int8_t,而我們傳入的200已經超過最大範圍,因此傳入的資料發生大型別到小型別的轉換;同時函式返回值是int8_t,兩個超過範圍的int8_t相加得不到200+200=400的數值,如果相加也出現溢位,那麼返回值更加不可測了。

函式返回值。

函式add2的引數和返回值都是uint16_t,我們傳入的兩個uint8_t被轉換為uint16_t,運算結果數值也是uint16_t,因此返回數值正確。

編譯執行:

在編寫程式的過程中,我們需要留意可能存在隱式型別轉換的地方,避免由於資料型別轉換導致的結果不可**。

嵌入式學習(二) 嵌入式系統C 語言

1 從 cpu 復位時的指定位址開始執行 2 跳轉至彙編 startup 處執行 3 跳轉至使用者主程式 main 執行,在 main 中完成 a.初試化各硬體裝置 b.初始化各軟體模組 c.進入死迴圈 無限迴圈 d呼叫各模組的處理函式 下面是幾個 著名 的死迴圈 1 作業系統是死迴圈 2 win3...

嵌入式C語言總結

這幾天花了兩天時間看了一些嵌入式c語言方面的內容,以下是一些讀書筆記,記錄一下。1 不能有返回值 2 不能向isr 傳遞引數 3 isr盡可能的短 4 printf有重入問題 1 中斷服務程式isr 2 硬體初始化 1 某io 晶元被定為在 cpu的儲存空間而非 io空間,而且暫存器對應於某特定位址...

嵌入式c語言優化

一.演算法和資料結構優化 1.針對應用的演算法優化,比如,在音訊編譯碼中,用fft實現時頻變換。2.c語言級別的優化,如排序演算法的選擇。3.資料結構的選擇,如果需要隨機訪問,則盡量選擇陣列,如果需要隨機插入刪除,則可以選擇鍊錶。4.盡量用指標代替資料操作,大部分編譯對於指標會生成更小更快的 5.盡...