嵌入式軟件開發 必須掌握的知識點(一)

1、CPU對數據兩種存儲模式:小端存儲和大端存儲 (Little-Endian and  Big-Endian)

如整數0x12345678在內存中應該如下存放:

地低: base   | base+1   | base+2   | base+3 |
           ------------------------------------------------ |
大端    |   12   |    34     |    56     |    78      |
            ----------------------------------------------- |
小端    |    78   |     56     |    34     |     12    |

 

程序如下:

       ...........

   union{
        char b;
        int a;
        }endiandata;//聯合體http://www.docin.com/p-4480156.html
 
        endiandata.a=0x12345678;
 
        printf("%x\n",endiandata.b);
 
        if(endiandata.b==0x78)
                printf("Little-Endian\n");
        else if(endiandata.b==0x12)
                printf("Big-Endian\n");
        else
                printf("Error\n");

........................

2、前置雙目運算符++a和後置雙目運算符a++

http://liuyunfeng484.blog.163.com/blog/static/668317152009817739170/

++a       { return *this    }    //先+1再反回

a++      { old = data; ++(*this);return Old}  //先返回再+1

當使用前綴用法,即先書寫自增/自減運算符再書寫其操作數時,程序首先對該操作數進行引用,再對其進行加1或減1及賦值;

當使用後綴用法,即先書寫操作數再書寫自增/自減運算符時,程序首先對操作數進行加1或減1及賦值,再對該操作數進行引用;

http://eol.bit.edu.cn/res2006/data/080605/U/100/bjjch/bjjch_02_04_01.htm

 

測試如下

#include"stdio.h"
int main()
{
        int a,b,c,d;
        a=10;
        b=a++;
        c=++a;
        d=10*a++;

        printf("b:%d\tc:%d\td:%d\n",b,c,d);
        return 0;
}

輸出結果爲

b:10    c:12    d:120

 

3、const int a(int const a)、const int *a、int * const a和int const * a const;

const int a(int const a) 兩個的作用是一樣,a是一個常整型數。

                   const int *a    意味着a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。

                  int * const a    意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。

          int const * a const   最後一個意味着a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。

 

關鍵字const的意義:

1) 關鍵字const的作用是爲給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數爲常量是爲了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)

2) 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。

3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。

 

 

4 、關鍵字volatile有什麼含意?並給出三個不同的例子

一個定義爲volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏的備份。下面是volatile變量的幾個例子:

1) 並行設備的硬件寄存器(如:狀態寄存器)

2) 一箇中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)

3) 多線程應用中被幾個任務共享的變量

 

 

volatile的重要性:

1)一個參數既可以是const還可以是volatile嗎?解釋爲什麼。

是的。一個例子是隻讀的狀態寄存器。它是volatile因爲它可能被意想不到地改變。它是const因爲程序不應該試圖去修改它。

2); 一個指針可以是volatile 嗎?解釋爲什麼。

是的。儘管這並不很常見。一個例子是當一箇中服務子程序修該一個指向一個buffer的指針時。

3); 下面的函數有什麼錯誤:

int square(volatile int *ptr)

{

        return *ptr * *ptr;

}

 

這段代碼的目的是用來返指針*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:

 

int square(volatile int *ptr)

{

     int a,b;

     a = *ptr;

     b = *ptr;

     return a * b;

}

 

由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:

 

long square(volatile int *ptr)

{

     int a;

     a = *ptr;

     return a * a;

}

 

5、中斷(Interrupts)

 

中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標準C支持中斷。具代表事實是,產生了一個新的關鍵字 __interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一箇中斷服務子程序(ISR),評論一下這段代碼的。

 

__interrupt double compute_area (double radius)

{

     double area = PI * radius * radius;

     printf("\nArea = %f", area);

     return area;

}

 

這個函數有太多的錯誤了,以至讓人不知從何說起了:

1)ISR 不能返回一個值。如果你不懂這個,那麼你不會被僱用的。

2) ISR 不能傳遞參數。如果你沒有看到這一點,你被僱用的機會等同第一項。

3) 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。

 

 

 

6、關鍵字static的作用

1)在函數體,一個被聲明爲靜態的變量在這一函數被調用過程中維持其值不變。

2) 在模塊內(但在函數體外),一個被聲明爲靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。

3) 在模塊內,一個被聲明爲靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地範圍內使用。

 

 7、uC/OS-II移植的的基本要求

對微處理器的基本要求

1)處理器的C編譯器能產生可重入代碼

2)用C語言就可以實現開關中斷

3)處理器至少能支持定時中斷,中斷頻率一般在10~100HZ之間

4)處理器能夠支持硬件堆棧,容量可達幾KB;

5)處理器有堆棧指針和讀/寫CPU其它寄存器、堆棧內容或內存的指令

對開發工具的要求

1)C編譯器必須支持彙編程序

2)C編譯器必須能支持可重入代碼,因爲uC/OS-II是一個可剝奪內核

3)C編譯器發佈包括彙編器、連接器和定位器。連接器用來將經編譯和彙編後產生的不同的模塊連接成目標文件。定位器用於將代碼和數據放置在目標處理器的指定內存映射空間中,

4)C編譯器必須支持從C中打開和關閉中斷

5)C編譯器必須支持用戶在C語言程序中嵌入彙編語言,這有利於用彙編語言來直接開關中斷

8、C語言中的for和while

 http://my.oschina.net/miaoyushun/blog/16093

當while 和for 的循環體內 是空語句時:

 i = 10; while(--i); for(i =10 ;i;i--); for(i =10 ;i;--i)

以上三條語句效率相同 對應1條彙編語句 2個機器週期

for(i =0 ;i<10;++i) for(i =0 ;i<10;i++)

以上兩條語句效率相同 對應2條彙編語句 3個機器週期

但while(i--); 效率很低 爲4條語句 6個機器週期

當while 和for 的循環體內 不是空語句時:

for(* ; i ; *) 的效率最高 依然是1條指令 2個機器週期

 for(* ; i<10 ; *) 的效率次之 2條指令 3個機器週期

 while(i--) 8個機器週期

while(--i) 6個機器週期

 while( i++ < * ) 10個機器週期

while( ++ i< * ) 8個機器週期

推薦使用 for(;i;)

另外 如果 循環變量 i 是通過函數參數 形式傳遞的值 for()的效率降低到 6-8個機器週期

總體來說: 如果循環變量是參數 且循環體爲空 while(--i); 是最高效的 其他情況建議 使用 for(*;i ;*){} while(i--)這個被大多數人看好的語句 無論哪種情況下 效率都是最低的;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章