編譯指示 pragma在DSP中的程式設計技巧

2021-10-18 22:27:44 字數 4855 閱讀 2345

編譯指示(pragma directives)可能是所有的預處理指令中最複雜的了,它的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對編譯器給出了如何處理特定的函式、物件和**段的方法,在保持與c/c++語言完全相容的情況下,給出主機(比如c28x)或作業系統(比如dsp/bios)專有的特徵。這些編譯指示的使用較為複雜,但是我們還必須要了解它們,因為它們是程式中必不可少的東西,例如#pragma data_section ( symbol , " section name 「);這樣的。但是往往講解它們的資料又不多(因為大部分資料集中在入門指南上面),所以在此我們就總結一下針對c28x編譯器的pragma指令,再遇到它們的時候就不會一頭霧水了。

1. check_misra

它的作用與在編譯器選項中使用–check_misra是相同的,都是對特定原始檔使能misra-c:2004規則檢查(****軟體可靠性聯會),使用方法是:

#pragma check_misra (」 ");

其中的rulespec是具體misra中的規則,使用方法請參考dsp程式設計技巧之12-揭開編譯器神秘面紗之**規範misra-c。

2. clink

clink指令可用於某段**或者某個資料符號,使用之後會在包含被作用符號的段中產生乙個.clink指示,表明在條件鏈結的情況下,如果這個段沒有被其它任何段引用的話,這個段可以被移除,從而減小鏈結輸出檔案的尺寸。使用方法是:

#pragma clink (symbol )

3. code_align

code_align用來沿著特定的對齊引數constant來對齊函式(從而可以讓cpu更快定址,更快執行指令)。當我們希望函式從特定的邊界開始的時候,這個指令非常有用。引數constant必須是2的冪(偶數對齊),使用方法是:

c**: #pragma code_align ( func, constant );

c++**: #pragma code_align ( constant );

注:在本文中,在c和c++**中,指令使用方法一樣時,不分別寫出,如不一樣則分c**和c++**分別寫出。c**中的#pragma指令一般需指定函式名,也即其作用域;c++**中的#pragma指令一般不帶有函式名,其作用域為緊鄰該指令後面的函式;下同。

4. code_section

code_section是較為常見的指令,預設情況下,**被存放在.text段中,使用此指令則用來指定並改變某段**所分配的段,其使用方法是:

c**: #pragma code_section (symbol , "section name 「)

c++**: #pragma code_section (」 section name ")

例如:char buffera[80];

char bufferb[80];

#pragma code_section(funca, 「codea」)

char funca(int i);

char funcb(int i);

void main()

char funca (int i)

char funcb (int j)

data_section

data_section可能是使用最多的pragma指令了,它用來定義儲存某個符號所使用的段,使用方法是:

c**: #pragma data_section ( symbol , " section name 「);

c++**: #pragma data_section (」 section name ");

例如:#pragma data_section(bufferb, 「my_sect」)

char buffera[512];

char bufferb[512];

6. 與診斷資訊有關的pragma

診斷資訊一般包括:提醒,警告,錯誤和不提示等幾個級別,使用與診斷資訊有關的pragma和使用相關的編譯器選項的結果是一樣的,其使用方法以及們的對應關係如下:

pragma對應的編譯器選項

有關診斷資訊的含義,請參考dsp程式設計技巧之7—揭開編譯器神秘面紗之預處理與診斷。

7. fast_func_call

使用這個指令,會在編譯時呼叫快速彙編指令ffc,而不是傳統的call指令來完成函式的跳轉,其使用方法是:

#pragma fast_func_call ( func );

它的使用範圍是受限的:僅限於呼叫返回lb *xar7指令的匯程式設計序。例如:

;匯程式設計序

_add_long:

add acc, *-sp[2]

lb *xar7

//呼叫彙編的c程式

#pragma fast_func_call (add_long);

long add_long(long, long);

void foo()

除此之外,如果使用該指令,編譯器會輸出警告資訊,並忽略其指示。

8. func_ext_called

在我們啟用程式級別的優化選項時(-o3),所有未直接或者簡介被main函式呼叫的函式都將被優化掉,但是這些函式也有可能被我們定義的某些彙編**使用到,所以使用func_ext_called可以在編譯時保留這些**,其使用方法是:

c**: #pragma func_ext_called ( func );

c++**: #pragma func_ext_called;

function_options

使用這個選項可以在編譯c/c++**中的某些函式時,使用額外的編譯器的命令列選項,實現與在命令列中輸入相關的命令同樣的效果。其使用方法是:

c**: #pragma function_options ( func, 「additional options」 );

c++**: #pragma function_options( 「additional options」 );

10. interrupt

使用這個選項可以在c**中直接操作中斷,其使用方法是:

c**: #pragma interrupt ( func );

c++**: #pragma interrupt ;

被該指令直接操作的函式將使用irp(中斷返回指標)來返回值。

在使用fpu時,中斷分為兩種:高優先順序中斷hpi和低優先順序中斷lpi,其中hpi使用快速的上下文儲存機制,不能被巢狀,lpi則與普通的c28x中斷機制一樣,並且可以被巢狀。此時可以增加第二個引數來控制:

c**: #pragma interrupt ( func , );

c++**: #pragma interrupt ( );

在dsp/bios和sys/bios hwi物件中,不能使用interrupt指令,因為hwi_enter/hwi_exit巨集和hwi解包器已經包含了該函式,此時使用該指令會產生負面的效果。

11. must_iterate

使用這個指令的情況下,我們確信某個for迴圈能夠執行指定的次數。使用這個指令能夠幫助編譯器確定迴圈的次數和最佳的實現方式,從而減小**的尺寸。其使用方法是:

#pragma must_iterate ( min, max, multiple );

min是迴圈的最小次數,max是最大執行次數,multiple則是迴圈次數的整數倍,如果這其中某個引數不存在,則可以省略,例如:

#pragma must_iterate(5); /* 最少迴圈5次 /

#pragma must_iterate(5, , 5); / max引數省略;迴圈次數是5的倍數次(至少1倍) /

pragma must_iterate(8, 48, 8);

/ 迴圈此時可能為8, 16, 24, 32, 40, 48 */

12. no_hooks

該指令阻止在呼叫函式時自動產生進入鉤子和退出鉤子,使用方法是:

c**: #pragma no_hooks ( func );

c++**: #pragma no_hooks;

reset_misra

顧名思義,這個指令會把misra-c:2004規則檢查恢復到它原先的設定狀態。例如,某條規則在命令列裡被使能,但是在某段**中被遮蔽了(某些原因導致它無法通過規則檢查),使用該指令會規則檢查重新使能。使用方法是:

#pragma reset_misra (" ")

14. retain

使用這個指令,可以避免某些符號在條件鏈結時被優化掉,從而在輸出檔案中保留它。使用方法是:

#pragma retain ( symbol )

這個指令與我們的第二條,clink的效果是整好相反的。

15. set_code_section與set_data_section

這兩條指令用來設定其後所有宣告的段。使用方法是:

c**: #pragma set_code_section (「section name」)

c++**: #pragma set_data_section (「section name」)

例如:#pragma set_data_section(「mydata」)

int x;

int y;

#pragma set_data_section()

其中的x和y都被會放入我們指定的段mydata中,直到我們使用空引數set_data_section(),之後的**或資料才會被放入預設的段之中。

16. unroll

unroll是「攤開」的意思,這個指令與for/while相關,意思是把n次的迴圈給展開,從而有個n份同樣的**。迴圈展開,是一種犧牲程式的尺寸來加快程式的執行速度的優化方法。可以手動程式設計完成,也可由編譯器自動優化完成。迴圈展開通過將迴圈體**複製多次實現。迴圈展開能夠增大指令排程的空間,減少迴圈分支指令的開銷。迴圈展開可以更好地實現資料預取技術。其使用方法是:

#pragma unroll( n );

只有在編譯器認為n是安全的(即展開之後確實都能執行),才能執行此操作。

Boost在linux中編譯

用boost 1 39 0版本作為例子 1 進入boost 1 39 0 tools jam src 2 執行.build.sh 或者在boost 1 39 0 tools jam 下執行.build dist.sh 3 編譯完成後在boost 1 39 0 tools jam src bin.li...

sizeof函式的使用及其在DSP中的應用

3 dsp中sizeof的用法 4 sizeof的用法問題 5 其他相關問題 sizeof是c c 中的乙個操作符 operator 簡單的說其作用就是返回乙個物件或者型別所佔的記憶體位元組數。c語言中,對 sizeof 的處理都是在編譯階段進行,所以它可以被當作常量表示式使用。其作用就是返回乙個物...

筆記 對volatile關鍵字在DSP中的理解

dsp將暫存器變數都對映到相應的暫存器位址,因此經常會見到這樣宣告的語句 volatile struct epwm regs epwm pwm ch 那麼,為什麼 需要vola tile 這個關鍵字呢?該單詞的意思是可變的,易變的。在dsp中,一些暫存器的值的變化有兩種情況 1 硬體上導致的變化,例...