嵌入式系統(tǒng)C語言編程基礎(chǔ)_第1頁
嵌入式系統(tǒng)C語言編程基礎(chǔ)_第2頁
嵌入式系統(tǒng)C語言編程基礎(chǔ)_第3頁
嵌入式系統(tǒng)C語言編程基礎(chǔ)_第4頁
嵌入式系統(tǒng)C語言編程基礎(chǔ)_第5頁
已閱讀5頁,還剩76頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、嵌入式系統(tǒng)C語言編程基礎(chǔ)楊高波SNBCPage 2目錄 關(guān)于本課程 C語言復(fù)習(xí) 編程規(guī)范 開發(fā)高效程序的技巧Page 3為什么學(xué)習(xí)本課程 會(huì)C語法與會(huì)用C語言寫程序是兩個(gè)概念 C的靈活性以及由此而產(chǎn)生的陷阱非常多 The Most Beautiful Language and Most Dangerous Language in the Programming World! 本課程將嵌入式系統(tǒng)中最基本的(最經(jīng)常用到的)概念與技巧介紹給大家Page 4小測驗(yàn)?Page 5Quiz 1 所有嵌入式系統(tǒng)的主流程最后都進(jìn)入一個(gè)死循環(huán),怎樣用C語言實(shí)現(xiàn)一個(gè)死循環(huán)?Page 6Quiz 2 while()

2、.和do.while()有什么區(qū)別?Page 7Quiz 3用變量a給出下列定義:a) 一個(gè)整型數(shù)b) 一個(gè)指向整型數(shù)的指針c) 一個(gè)有10個(gè)整型數(shù)的的數(shù)組d) 一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的Page 8Quiz 4 關(guān)鍵字static的作用是什么?Page 9Quiz 5 關(guān)鍵字const的作用是什么?Page 10Quiz 6 定義一個(gè)標(biāo)準(zhǔn)宏MIN ,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)。Page 11Quiz 7 嵌入式系統(tǒng)中經(jīng)常要對變量或寄存器進(jìn)行位操作。給定一個(gè)int型變量a,寫兩段代碼,第一個(gè)將a的bit 3置為1,第二個(gè)將a的bit 3置為0。以上兩個(gè)操作中,要保

3、持其它位不變。Page 12Quiz 8 嵌入式系統(tǒng)具有經(jīng)常去直接訪問物理地址的特點(diǎn)。在某工程中,要求設(shè)置一絕對地址為0 x5a00 的整型變量的值為0 xaa55。寫代碼去完成這一任務(wù)。Page 13Quiz 9 下面這段代碼的輸出是什么?void foo(void)unsigned int a = 6;int b = -20;(a+b 6) ? puts(6) : puts(6);Page 14Quiz 10 請?jiān)u論下面一段程序代碼:void test()char string10;char *str = “0123456789”;strcpy(string,str);Page 15Qui

4、z 11 請?jiān)u論下面一段程序代碼:void GetMemory(char *p)p = (char *)malloc(0 x20);void Test(void)char *str = NULL;GetMemory(str);strcpy(str,”Hello World!”);printf(str);Page 16Quiz 12 中斷是嵌入式系統(tǒng)的重要組成部分。請?jiān)u論下面一段中斷服務(wù)子程序代碼:_interrupt double compute_area (double radius)double area = PI * radius * radius;printf(nArea = %f,

5、area);return area;Page 17Answer!Page 18Quiz 1 Answer while(1).Page 19Quiz 2 Answer while().為入口條件循環(huán),即在每次執(zhí)行循環(huán)之前先檢查判斷條件;do.while()為退出條件循環(huán),即在執(zhí)行循環(huán)之后再檢查判斷條件。Page 20Quiz 3 Answer a) int a;b) int *a;c) int a10;d) int *a10;Page 21Quiz 4 Answer 在C 語言中,關(guān)鍵字static 有三個(gè)明顯的作用:1) 在函數(shù)體內(nèi),一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。2

6、) 在模塊內(nèi)(但在函數(shù)體外),一個(gè)被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個(gè)本地的全局變量。3) 在模塊內(nèi),一個(gè)被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。Page 22Quiz 5 Answer const是constant的縮寫,“恒定不變”的意思。被const修飾的東西都受到強(qiáng)制保護(hù),可以預(yù)防意外的變動(dòng),能提高程序的健壯性。 const常量與#define常量:前者有數(shù)據(jù)類型,后者只是字符替換(而且可能產(chǎn)生意料不到的錯(cuò)誤),所以編譯器可以對前者進(jìn)行安全性檢查。Page 23Quiz 6 An

7、swer #define MIN(A,B) (A) = (B) ? (A) : (B) #define宏的副作用,下面的代碼執(zhí)行后會(huì)發(fā)生什么事:least = MIN(*p+, b);Page 24Quiz 7 Answer const int BIT3 = 0 x016”,原因是當(dāng)表達(dá)式中存在有符號類型和無符號類型時(shí)所有的操作數(shù)都自動(dòng)轉(zhuǎn)換為無符號類型。 因此-20 變成了一個(gè)非常大的正整數(shù),所以該表達(dá)式計(jì)算出的結(jié)果大于6。這一點(diǎn)對于頻繁用到無符號數(shù)據(jù)類型的嵌入式系統(tǒng)來說是豐常重要的。Page 27Quiz 10 Answer 字符串str需要11個(gè)字節(jié)才能存放下(包括末尾的0),而strin

8、g只有10個(gè)字節(jié)的空間,所以strcpy會(huì)導(dǎo)致數(shù)組越界。 Page 28Quiz 11 Answer 編譯器總是要為函數(shù)的每個(gè)參數(shù)制作臨時(shí)副本,指針參數(shù)p的副本是_p,編譯器使 _p = p。本例中,_p申請了新的內(nèi)存,但只是_p的值改變了,p的值卻絲毫未變,仍然為NULL。事實(shí)上,每執(zhí)行一次GetMemory就會(huì)泄漏一塊內(nèi)存。Page 29Quiz 12 Answer 1)ISR不能返回值;2)不能向ISR傳遞參數(shù);3)ISR應(yīng)該是短而有效率的,因而在ISR中做浮點(diǎn)運(yùn)算、使用printf等是不明智的,會(huì)經(jīng)常有重入和性能上的問題。Page 30還是先復(fù)習(xí)一下C吧!Page 31C語言復(fù)習(xí) 1)

9、循環(huán)與分支2)作用域與存儲(chǔ)類3)內(nèi)存與指針4)位操作5)預(yù)編譯處理Page 32循環(huán)與分支 1)幾種循環(huán)語句:for(initialize;test;update)body;while(test)body;dobody;while(test); 2)循環(huán)輔助手段:break語句用于跳出循環(huán),continue語句用于結(jié)束本次循環(huán)。Page 33循環(huán)與分支 3)三種形式的if語句:if(expression).if(expression).else.if(expression1).else if(expression).else.Page 34循環(huán)與分支 4)條件運(yùn)算符?:expression1

10、? expression2 : expression3 如果expression1為真,整個(gè)表達(dá)式的值為expression2的值,否則為expression3的值; 是if.else.的簡寫形式,但是編譯器可以產(chǎn)生比if.else.更優(yōu)化的代碼。Page 35循環(huán)與分支 5)多重選擇:switchswitch(expression)case constant1: statements; break;case constant2: statements; break;.default: statements; break;switch判斷表達(dá)式必須具有整數(shù)值,case標(biāo)簽必須是整數(shù)常量或整數(shù)常

11、量表達(dá)式。Page 36C語言復(fù)習(xí) 1)循環(huán)與分支2)作用域與存儲(chǔ)類)作用域與存儲(chǔ)類3)內(nèi)存與指針4)位操作5)預(yù)編譯處理Page 37作用域與存儲(chǔ)類 1)作用域 代碼塊作用域(局部變量)代碼塊:包含在開始花括號和對應(yīng)結(jié)束花括號之內(nèi)的一段代碼。作用域:從定義變量位置到該代碼塊的末尾。 文件作用域(全局變量)在所有函數(shù)之外定義的變量具有文件作用域。作用域:從定義變量位置到包含該定義的文件的結(jié)尾處。在其它位置使用該變量應(yīng)用extern來聲明該變量。Page 38作用域與存儲(chǔ)類 2)存儲(chǔ)時(shí)期 靜態(tài)存儲(chǔ)時(shí)期:程序運(yùn)行期間一直存在,給變量分配固定的存儲(chǔ)空間;所有全局變量具有靜態(tài)存儲(chǔ)時(shí)期(具有靜態(tài)存儲(chǔ)時(shí)期

12、的并不都是全局變量),但是修飾全局變量的關(guān)鍵詞static表明的是鏈接類型,并非存儲(chǔ)時(shí)期。 動(dòng)態(tài)(自動(dòng))存儲(chǔ)時(shí)期:運(yùn)行期間根據(jù)需要?jiǎng)討B(tài)的給變量分配存儲(chǔ)空間。Page 39作用域與存儲(chǔ)類 3)5種存儲(chǔ)類存儲(chǔ)類存儲(chǔ)時(shí)期作用域鏈接聲明方式自動(dòng)自動(dòng)代碼塊空代碼塊內(nèi)寄存器自動(dòng)代碼塊空代碼塊內(nèi),使用關(guān)鍵字register外部靜態(tài)靜態(tài)文件外部所有函數(shù)之外內(nèi)部靜態(tài)靜態(tài)文件內(nèi)部所有函數(shù)之外,使用關(guān)鍵字static代碼塊靜態(tài)靜態(tài)代碼塊空代碼塊內(nèi),使用關(guān)鍵字staticPage 40C語言復(fù)習(xí) 1)循環(huán)與分支2)作用域與存儲(chǔ)類3)內(nèi)存與指針)內(nèi)存與指針4)位操作5)預(yù)編譯處理Page 41內(nèi)存與指針 1)內(nèi)存分配方

13、式 從靜態(tài)存儲(chǔ)區(qū)分配。內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好,這塊內(nèi)存在程序的整個(gè)運(yùn)行期間都存在。例如全局變量,static變量; 從棧上創(chuàng)建。在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限; 動(dòng)態(tài)內(nèi)存分配。程序在運(yùn)行的時(shí)候由程序員自己負(fù)責(zé)申請和釋放內(nèi)存。Page 42內(nèi)存與指針 2)內(nèi)存陷阱 C語言的靈活性,指針的應(yīng)用,以及C語法的寬容性很容易造成代碼的錯(cuò)誤,這其中最主要的就是內(nèi)存單元的溢出。a) 堆棧溢出b) 數(shù)組越界. 將錯(cuò)誤鎖定在一個(gè)函數(shù)中以后,首先應(yīng)該關(guān)注內(nèi)存的問題。Pag

14、e 43內(nèi)存與指針 舉例,看看下面這段代碼有什么問題char *DoSomething()char i32*1024;.return i;兩個(gè)重大問題:兩個(gè)重大問題:1、臨時(shí)變量在堆棧上創(chuàng)建,太大的、臨時(shí)變量在堆棧上創(chuàng)建,太大的臨時(shí)變量數(shù)組會(huì)沖掉堆棧;臨時(shí)變量數(shù)組會(huì)沖掉堆棧;2、返回堆棧中的地址是沒有意義的,、返回堆棧中的地址是沒有意義的,因?yàn)槎褩V械膬?nèi)容永遠(yuǎn)是不確定的。因?yàn)槎褩V械膬?nèi)容永遠(yuǎn)是不確定的。Page 44內(nèi)存與指針 數(shù)組越界的危險(xiǎn) 臨時(shí)數(shù)組:在棧上創(chuàng)建,因此臨時(shí)數(shù)組越界有可能導(dǎo)致某些局部變量莫明其妙被改,函數(shù)返回時(shí)崩潰等等; 全局?jǐn)?shù)組:在靜態(tài)存儲(chǔ)區(qū)創(chuàng)建,因此全局?jǐn)?shù)據(jù)越界有可能導(dǎo)致某

15、些全局變量莫明其妙被改,被沖的動(dòng)態(tài)內(nèi)存無法釋放等等。Page 45內(nèi)存與指針 3)指針 指針是什么?指針是一個(gè)變量,它的值是另外一個(gè)變量的地址。 指針的類型指針?biāo)赶虻淖兞康念愋停褪侵羔樀念愋?。舉例,右邊的運(yùn)算有何不同:int X2, *pX=&X0;pX+;char Y2,*pY=&Y0;pY+;Page 46內(nèi)存與指針 指針的三要素 1、指針指向的地址;2、指針指向地址上的內(nèi)容;3、指針本身的地址; 舉例:int A, *pA, *ppA;pA = &A;ppA = &pA;Page 47內(nèi)存與指針 指針的大?。ㄖ羔樧兞空加玫膬?nèi)存空間) 舉例,以下為ARM

16、平臺(tái)下的一段32位C程序,請計(jì)算sizeof的值。char str = “Hello”;char *p = str;int n = 10;sizeof(str) = ?sizeof(p) = ?sizeof(n) = ?sizeof(str) = 6sizeof(p) = 4sizeof(n) = 4Page 48內(nèi)存與指針 指針的初始化 指針變量在沒有被初始化之前,它的值是隨機(jī)的;一個(gè)指向不明的指針是非常危險(xiǎn)的。 當(dāng)創(chuàng)建一個(gè)指針時(shí),系統(tǒng)只分配了用來存儲(chǔ)指針本身的內(nèi)存空間,并不分配用來存儲(chǔ)數(shù)據(jù)的內(nèi)存空間。使用指針之前,必須給它賦予一個(gè)已分配的內(nèi)存地址。Page 49內(nèi)存與指針 指針與數(shù)組舉例,

17、下列操作是否合法:int a4,*p;p = a;*(a+2) = 0 x00;p2 = 0 x01;/等價(jià)于p=&a0;/等價(jià)于a2;/等價(jià)于*(p+2);但是數(shù)組名不同于指針:數(shù)組名a是指向數(shù)組起始位置的“常量”。因此不能對數(shù)組名進(jìn)行賦值操作。a = p;/錯(cuò)誤a+;/錯(cuò)誤Page 50內(nèi)存與指針 指針與數(shù)組什么時(shí)候是相同的舉例,以下為ARM平臺(tái)下的一段32位C程序,請計(jì)算sizeof的值。void Func(char a100)sizeof(a) = ?sizeof(a) = 4(1)數(shù)組名作為函數(shù)形參時(shí),在函數(shù)體內(nèi),其失去了本身的內(nèi)涵,僅僅只是一個(gè)指針;(2)很遺憾,在失去其內(nèi)

18、涵的同時(shí),它還失去了其常量特性,可以作自增、自減等操作,可以被修改。Page 51內(nèi)存與指針 數(shù)組與指針運(yùn)用規(guī)則數(shù)組數(shù)組聲明聲明使用使用定義,如char a10不能寫成指針的形式extern,如extern char a不能寫成指針的形式func(char a);或func(char *a)函數(shù)參數(shù)可以寫成指針的形式c = ai;或c = *(a+i);可以寫成指針的形式Page 52C語言復(fù)習(xí) 1)循環(huán)與分支2)作用域與存儲(chǔ)類3)內(nèi)存與指針4)位操作)位操作5)預(yù)編譯處理Page 53位操作 1)位操作的用途 硬件寄存器控制; 壓縮和加密操作; 提高程序運(yùn)行效率; .因?yàn)槲皇浅绦蚩梢圆僮鞯淖?/p>

19、小數(shù)據(jù)單位,所以理論上可以用“位操作”完成所有的運(yùn)算與操作。Page 54位操作 2)位運(yùn)算符 位邏輯運(yùn)算符& 位與(兩個(gè)數(shù)對應(yīng)位都為1結(jié)果才為1)| 位或(兩個(gè)數(shù)對應(yīng)位有一個(gè)為1結(jié)果則為1 ) 位異或(兩個(gè)數(shù)對應(yīng)位不同結(jié)果則為1 ) 按位取反(單目運(yùn)算符) 移位運(yùn)算符 右移 Page 55位操作 3)用法:掩碼位操作符通常跟掩碼一起用。掩碼是某些位為開而某些位為關(guān)的位組合。例:flag &= MASK;00000 01010110 11000000010MASKflag&=Page 56位操作 4)用法:打開位、關(guān)閉位、轉(zhuǎn)置位 打開位:flag = flag | MA

20、SK;或flag |= MASK; 關(guān)閉位: flag = flag & MASK;或flag &= MASK; 轉(zhuǎn)置位: flag = flag MASK;或flag = MASK;Page 57位操作 5)用法:查看某一位的值 錯(cuò)誤用法:if(flag = MASK) 正確用法:if(flag&MASK) = MASK)位運(yùn)算符的優(yōu)先級低于=,因此需要在flag&MASK的兩側(cè)加上圓括號。Page 58位操作 6)用法:移位操作unsigned char ch=0 x07;/00000111unsigned char i;i = ch 2;00000 111

21、11000 00000000 001左移右移Page 59C語言復(fù)習(xí) 1)循環(huán)與分支2)作用域與存儲(chǔ)類3)內(nèi)存與指針4)位操作5)預(yù)編譯處理)預(yù)編譯處理Page 60預(yù)編譯處理 C編譯系統(tǒng)在對程序進(jìn)行編譯之前,先進(jìn)行預(yù)處理。C提供的預(yù)處理功能主要有以下三種: 宏定義 文件包含 條件編譯Page 61預(yù)編譯處理 1)宏定義 類對象宏例:#define STX 0 x02 類函數(shù)宏例:#define SQUARE(x) (x)*(x) 幾點(diǎn)說明:a.宏定義不是C語句,不在行末加分號;b.宏名有效范圍為從定義處到本源文件結(jié)束;c.在宏定義時(shí),可以引用已經(jīng)定義的宏名;d.宏替換不占運(yùn)行時(shí)間,只占編譯時(shí)

22、間;Page 62預(yù)編譯處理 2)文件包含:#include 預(yù)處理器發(fā)現(xiàn)#include后,就會(huì)尋找后跟的這個(gè)文件并把這個(gè)文件的內(nèi)容復(fù)制到當(dāng)前位置替換#include指令; 使用#include指令的一些例子:#include 從標(biāo)準(zhǔn)庫路徑開始搜索文件#include “def.h”從當(dāng)前工作路徑開始搜索文件#include “/usr/head/def.h”搜索“/usr/head/”目錄Page 63預(yù)編譯處理 3)條件編譯 條件編譯指不對整個(gè)程序編譯,而是編譯滿足條件的那部分。條件編譯有以下幾種形式:a. #ifdef 標(biāo)識(shí)符 程序段1; #else 程序段2; #endif它的作用:當(dāng)標(biāo)識(shí)符在前面已經(jīng)定義過,則對程序段1進(jìn)行編譯,否則對程序段2進(jìn)行編譯。Page 64預(yù)編譯處理b. #ifndef 標(biāo)識(shí)符程序段1;#else程序段2;#endif它的作用和#ifdef相反,當(dāng)標(biāo)識(shí)符之前沒被定

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論