17條嵌入式C語言編程小知識總結


1.  流水線被指令填滿時才能發揮最大效能,即每時鍾周期完成一條指令的執行( 僅指單周期指令 )
如果程序發生跳轉,流水線會被清空,這將需要幾個時鍾才能使流水線再次填滿。因此,盡量少的使用跳轉指令可以提高程序執行效率,解決發案就是盡量使用指令的“條件執行”功能。
2.  Lpc2200 系列中:
可以通過過下面的程序延遲10 毫秒:
for(i=0;i<200;i++)
{
for(j=0;j<200;j++);
}
3.  通過下面語句將一個 16 位的變量放在兩個 8 位的變量中。
//IP 數據報總長度高字節
IpHeadUint8[10]=(IpHead.e_ip.Crc&0xff00)>>8;
//IP 數據報總長度低字節
IpHeadUint8[11]=IpHead.e_ip.Crc&0x00ff;
4.  在對全部數組元素賦初值時,可以不指定數組長度。
eg;inta={1,2,3,4,5};
但如果當輸出第a[5] 以上的元素時,系統回輸出隨機數值,所以使用此方法時,不能使用超過初始值元素以上的元素。
5.  由於 ADS 先天性的對 printf 不支持 ; 因此不便於我們調試,可以利用串口輸出來代替 printf 來調試。
6.  用或運算,可使某位置為 1 ,其它位不變
eg: PINSEL0 |= 0x00000005; // 設置串口引腳
使第0 位和第二位置一,其他位不變。
7.  函數指針
1> C 語言中函數名直接對應於函數生成的指令代碼在內存中的地址,因此函數名可以直接賦給指向函數的指針。
2>  調用函數實際上等同於“調用指令 + 參數傳遞處理 + 回歸位置入棧”,本質上最核心的操作是將函數生成的目標代碼的首地址賦給 CPU PC 寄存器。
3>  因為函數調用的本質是跳轉到某一個地址單元的 code 去執行,所以可以“調用一個根本就不存在在函數實體。
4> int (*p); 定義 p 是一個指向函數的指針變量,次函數返回帶回整型的返回值。 *P 兩側的括號不能省略,表示 p 先於 * 結合,是指針變量,然后再與后面的結合,表示此指針指向函
區別int *p 表示這個函數的返回值是指向整型變量的指針。
說明:
(1)  指向函數的指針變量的一般定義形式為:
數據類型 (* 指針變量名 );
1>  此處的“數據類型”是指函數返回值的類型
(2)  返回指針值的函數:
類型名 * 函數名 ( 參數表 )
eg: int * func(int x,int y)
func 是函數名,調用它以后能返回一個指向整型數據的指針。 x,y func 的形參。區別方法:
a. 從右往左找第一個括號,括號里面的是函數的形參。
b. 括號外面的第一個標識符是函數的名字,函數前面的表示函數的返回數值。
8.  數組指針
1>int (*p)[4]
表示*p 4 個元素,每個元素為整型。也就是 p 所指的對象有 4 個整型元素的數組,既 P 是行指針。
2>  指針數組
Ø  一個數組,其元素均為指針類型數據,稱為指針數組 ; 即指針數組中的每一個元素都相當於一個指針變量。
Ø  一維指針數組的定義形式為:
類型名 * 數組名 [ 數組長度
eg int *p[4]:
作用:它用於指向若干個字符串,使字符串處理更加方便靈活。適用於一個二維字符串數組,其中每一行的字符數組的長度各不相同
eg:char * name={ Follow me , BASIC , GreatWall };
9.  結構體
1>  可以用結構體變量做實參。但是用結構體變量作實參時,采取的是“值傳遞”的方式,將結構體變量所占的內存單元的內容全部順序遞給形參。形參也必須是同類型的結構體變量。
eg:pint(su);// 注在此處 su 為結構體
注:這種傳遞方式在空間和時間上開銷較大,如果結構體的規模較大時,開銷是很可觀的。
2>  用直向結構體變量 ( 或數組 ) 的指針作實參,將結構體變量 ( 或數組 ) 的地址傳給形參
eg:print(&su);// 注在此處 su 為結構體
10.  共用體
1>  共用體把幾種不同數據類型的變量存放在同一塊內存里。公用體中的變量共享同一塊內存。
2>  定義公用體類型變量的一般形式為:
union  共用體名
{
成員列表;
} 變量列表 ;
3> 在共用體中同一塊內存可以用來存放幾種不同類型的數據,但在某一時刻只能在其中存放一個成員變量。共用體變量中起作用的成員是最后一次存入的數據。
eg: union data
{
int i;
char c;
double d;
};
union data a;
共用體變量a 中的成員 i,c,d 三個變量在內存中從同一個地址開始存儲。如進行如下賦值:
a.i = 100;
a.c =  A ;

 

那么此時共用體變量a 中的成員 i 已經沒有值了,因為存儲該值的內存現在已經被用來存儲成員 c 的值了。
3>  共用體變量的長度取決於其成員的最大長度:
說明:
結構體變量所占內存的長度是各個成員的總和,每個成員分別占有自己的存儲空間。共用體變量所占內存的長度是其最長成員的長度。當然,編譯器出於提高訪問效率的目的,在編譯分配存儲空間時往往要進行對齊操作。
對齊操作以最大基本類型為准。即以最大基本類型為基本單元。若按實際算下的長度不是基本單元的整數倍,則其實際長度應該是基本單元的整數倍。
( TurboC 中不進行對齊,在 Linux 中進行對齊 )
11. CPU字長與 存儲器位寬不一致處理
例如:使用共用體來解決這一沖突:
union send_temp{
uint16 words;
uint8 bytes[2];
}send_buff;
eg:send_buff.bytes[0]=a;// 此處 8
send_buff.bytes[1]=b;// 此處  8 ;
此時就將8 位字拼成了 16 位字存儲了。
發送時send(send_buff.words) 就可以每次發送一個 16 位的數據了。
12. C 語言符號優先級:
1> 復合賦值運算符號:
a+=3*5;
等價於a=a+(3*5);
13.  一個常見的調試策略是把一些printf 函數的調用散布於程序中,確定錯誤出現的具體位置。
但是,這些函數調用的輸出結果被寫入到緩沖區中,並不立即顯示於屏幕上。事實上,如果程序失敗,緩沖輸去可能不會被實際寫入,因此得到的錯誤位置就是錯誤的。解決的方法是在每個用於調試的printf 函數之后立即調用 fflush 函數即可得到。
printf( something or other );
fflush(stdout);
14. 關鍵字 volatile 的用法
volatile 變量可能用於如下幾種情況:
1> 設備的硬件寄存器 ( 如:狀態寄存器 )
2> 一個中斷服務子程序中會訪問到的全局變量
3> 多線程應用中被幾個任務共享的變量。
15. 關鍵字 register 的用法:
當對一個變量頻繁被讀寫時,需要反復訪問內存,從而花費大量的存取時間。為此,C 語言提供了一種變量,即寄存器變量。這種變量存放在 CPU 的寄存器中,使用時,不需要訪問內存,而直接從寄存器中讀寫,從而提高效率。寄存器變量的說明符是 register 。對於循環次數較多的循環控制變量及循環體內反復使用的變量均可定義為寄存器變量,而循環計數是應用寄存器變量的最好候選者。
(1)  只有局部自動變量和形參才可以定義為寄存器變量。因為寄存器變量屬於動態存儲方式,凡需要采用靜態存儲方式的量都不能定義為寄存器變量,包括:模塊間全局變量、模塊內全局變量、局部 static 變量 ;
(2) register 是一個 " 建議 " 型關鍵字,意指程序建議該變量放在寄存器中,但最終該變量可能因為條件不滿足並未成為寄存器變量,而是被放在了存儲器中,但編譯器中並不報錯 ( C++ 語言中有另一個 " 建議 " 型關鍵字: inline)
16. 對於程序代碼,已經被燒錄在 FLASH ROM 中,我們可以讓 CPU 直接從其中讀取代碼執行,但通常這不是一個好辦法,我們最好在系統啟動后將 FLASH ROM 中的目標代碼拷貝入 RAM 中后再執行以提高取指令速度。
CPU 對各種存儲器的訪問速度,基本上是:
CPU 內部 RAM >  外部同步 RAM >  外部異步 RAM > FLASH/ROM
17.  宏定義
C 語言中,宏是產生內嵌代碼的唯一方法。對於嵌入式系統而言,為了能達到性能要求,宏是一種很好的代替函數的方法。
1> 宏定義“像”函數 ;
2> 宏定義不是函數,因而需要括上所有“參數” ;
3> 宏定義可能產生副作用。因而不要給宏定義傳入有副作用的 " 參數 "


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM