1. 程式人生 > >嵌入式軟體開發 必須掌握的知識點(一)(有錯還望指點^_^)

嵌入式軟體開發 必須掌握的知識點(一)(有錯還望指點^_^)

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--)這個被大多數人看好的語句 無論哪種情況下 效率都是最低的;