嵌入式編程

【1】用#define聲明一個常數,用以表示一年中有多少秒

#define SECONDS_PER_YEAR (60*60*24*365)UL

說明:首先,末尾#define語法末尾不能有分號;

      其次,計算式最好帶括號;

      第三,這個表達式會使16位機的整型數溢出,因此需要用長整型符號L告訴編譯器這個常數是長整型數,末尾用UL(無符號長整型)。


【2】用C編寫死循環

第一種方案:while(1){}

第二種方案:for(;;){}

第三種方案:Loop:

            ...

            goto Loop;    //這種方案是用匯編寫的


【3】訪問特定內存位置:

     在某工程中,一個整型變量的絕對地址是0x67a9,請將其設置爲0xaa55,並且已知編譯器是一個純粹的ANSI編譯器,請編寫代碼

int* ptr;

ptr=(int*)0x67a9;

*ptr=0xaa55;


【4】對中斷服務代碼的評論

wKioL1Y8z2ixVzXdAACasjDKVUM466.jpg

以上程序有如下幾個錯誤:

1、ISR不能返回一個值;

2、ISR不能傳遞參數,即不能有形參;

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

4、printf()經常出現重入和性能上的問題,


【5】對整數自動轉換原則的理解

wKiom1Y80GbgoLcrAACQpGP2HK0953.jpg

C語言中,整數自動轉換原則是:當表達式中同時存在有符號和無符號類型時,所有的操作數都自動轉換成無符號類型。因此,上面程序中,第5行,a+b,a是無符號整型,b是有符號整型,二者相加,則b自動轉換成無符號整型,-20變成了一個非常大的正整數,那麼顯然,此時a+b>6是成立的,因此,上面程序最終輸出的結果是“>6”。


【6】關鍵字static的作用

1、在函數體內,局部的stati變量。作用域在函數體內,生存期卻爲程序的生命週期。一個被聲明爲靜態的變量在這一函數被調用過程中維持其值不變,即本次訪問該變量時訪問到的是上次調用後的值。因爲它被分配在靜態存儲區內,函數結束調用後並不釋放單元,但是在其它的作用域無法訪問。當再次訪問這個函數時,這個局部的靜態變量還存活,因此訪問到的是上次調用後的值。

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

3、在文件模塊內,一個被聲明爲靜態的函數只可以被這個模塊內的其它函數調用。即這個函數被限制在聲明它的本地範圍內。


【7】與全局對象相比,使用靜態數據成員有什麼優勢

1、靜態數據成員沒有進入程序的全局名字空間,因此不存在與程序中其它全局名字衝突的問題。

2、使用靜態數據成員可以隱藏信息,因爲靜態數據成員可以是private成員,而全局變量不能。


【8】關鍵字volatile的含義

定義爲volatile的變量可能會被意想不到地改變,這樣編譯器就不會去假設這個變量的值。準確地說,優化器在用到volatile變量時必須小心地重新讀取該變量的值,而不是使用保存在寄存器裏的備份。使用volatile變量的地方如:

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

2、一箇中斷服務子程序中會訪問到的非自動變量。

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


【9】判斷處理器使用Big_endian還是Little_endian模式存儲數據

編寫一個函數,若處理器使用Big_endian模式存數數據,則返回0;若是用Little_endian模式存儲數據,則返回1。

分析:首先,應該瞭解Little_endian和Big_endian模式有所瞭解,採用Little_endian模式的CPU對操作數的存儲方式是從低字節到高字節,而Big_endian模式對操作數的存儲方式是從高字節到低字節。

例如,16位數0x1234在Little_endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)爲:

0x4000:    0x34

0x4001:    0x12

而在Big_endian模式CPU內存中的存放方式爲:

0x4000:    0x12

0x4001:    0x34


32位寬的數0x12345678在Little_endian模式CPU內存中的存放方式爲:

0x4000:    0x78

0x4001:    0x56

0x4002:    0x34

0x4003:    0x12

而在Big_endian模式CPU內存中存儲方式爲:

0x4000:    0x12

0x4001:    0x34

0x4002:    0x56

0x4003:    0x78


該函數爲:

wKiom1ZAmjmyfUPtAAAW9gVRFEo193.png

在聯合體中定義了兩個成員int和char,而聯合體的大小=sizeof(int)=4,因此該聯合體在內存中佔4個字節的大小,假設佔用的內存地址爲:0x1000~0x1003,那麼當給a賦值1時,如果按Little_endian方式存放該數據,則:

0x1000:   0x01

0x1001:    0x00

0x1002:    0x00

0x1003:    0x00

那麼這個數值1應該存放於地址0x1000中

而聯合體有一個特性:成員都從低地址開始存放,所以當c.b=1時,那就證明數值1是存儲於地址0x1000中的,那麼久可以證明是Little_endian方式存儲。


如果按Big_endian方式存放a的數值1,則

0x1000:    0x00

0x1001:    0x00

0x1002:    0x00

0x1003:    0x01

由聯合體的特性可知,當以Big_endian方式存儲的時候,c.b=0


【10】判斷處理器字長

unsigned int CompareZero=~0

cout<<hex<<CompareZero<<endl;


【11】找錯(對靜態成員與非靜態成員的理解)

wKioL1ZBpsCjBqMtAAEl7b81tso746.jpg

wKiom1ZBpnmgNK75AAHlwbRhE94387.jpg

上面程序中,i爲靜態成員變量,func2()爲靜態成員函數

第9行,test(int a):i(1),j(a) {}  根據規定,初始化列表的初始化順序 應該與 變量聲明的順序一致,而不是按照出現在初始化列表中的順序,從第7、8行可以看到,變量聲明順序先是i,然後再j,那麼在第9行中,也應該先初始化i,再初始化j,那麼此時應該i=1,j=a=2,這樣看似沒有錯,但是,忽略了一個細節,i是靜態成員變量。

爲了與非靜態成員變量相區別,i是不能再類的內部被初始化的。

可以在類的外部進行初始化,如,先把第9行改爲,test(int a):j(a) {}

然後再在第13行,添加:int test::i=1;

第16行,定義func2函數,首先該函數爲靜態成員函數,它想訪問靜態成員變量i,以及普通變量j,但是靜態成員函數只能訪問靜態成員變量,並不能訪問非靜態成員,因此無法訪問j,此行應該改爲:
void test::func2()    {cout<<i<<endl;}

需要注意的是:

1、靜態數據成員必須在類外面初始化,以示與普通數據成員的區別。

2、靜態數據成員以及靜態函數成員,不屬於類的對象,因此沒有this指針,也就無法調用類的非靜態成員,它是爲類的所有的對象所共享。






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