3

我目前正在爲微控制器編寫代碼;由於ATMega128沒有硬件乘法器或分頻器,因此這些操作必須用軟件完成,並且佔用相當數量的週期。但是,爲了代碼的可移植性和易用性,我不希望將預先計算的值硬編碼到我的代碼中。因此,例如,我有許多依賴於系統時鐘頻率的任務。目前我運行在16MHz,但是我應該選擇降低它,比如說爲了降低電池應用的功耗,我想改變一行代碼而不是很多。那麼,C預處理器可以計算算術表達式,然後將結果「粘貼」到我的代碼中,而不是將原始表達式「粘貼」到代碼中?如果是這樣,我將如何去做這件事?他們的編譯器選項和我需要考慮的是什麼?C預處理器可以執行算術運算嗎?如果是這樣,怎麼樣?

注:我想要計算的值是常數值,所以我沒有理由認爲這不是一個功能。

+1

如果表達式是常量,它們是不是被編譯器優化掉了呢? –

+0

http://stackoverflow.com/a/1560385/995714 –

+0

的副本嗯,有預處理器庫,可能有一個給你,它主要取決於你定位的C語言版本,例如C99和上面有P99 http://p99.gforge.inria.fr/ – user2485710

回答

3

它可以但不是必要的:除非您真的想生成以某種方式涉及數字的新標識符(例如func1,func2之類的東西),否則實際上並不需要涉及預處理器。

1 + 2 * 3這樣的表達式,其中所有元素都是編譯時常量的整數值,將在編譯時被單一結果替換(這或多或少被C標準要求,所以它不是「真正」的優化)。所以只需要#define常量,你需要命名一個可以從一個地方改變的值,確保表達式不涉及任何運行時變量,除非你的編譯器有意讓你的方式,你應該沒有運行時操作擔心。

+0

好的,無論哪種方式,我的表達式將在編譯時被單個常量替換(假設我的'#define'中沒有變量)? – audiFanatic

+0

爲了以防萬一,我會仔細檢查裝配。並非所有嵌入式C編譯器都遵循C規範;有些偏離很大。 – nneonneo

+2

@Leushenko在第二種情況下,甚至可以使用枚舉而不是定義,這樣程序更容易調試,而且根本不需要預處理器。 –

0

我使用gcc -E編譯了包含以下行的文件。

#define MUL(A, B) ((A)*(B)) 

#define CONST_A 10 
#define CONST_B 20 

int foo() 
{ 
    return MUL(CONST_A, CONST_B); 
} 

產量爲:

# 1 "test-96.c" 
# 1 "<command-line>" 
# 1 "test-96.c" 





int foo() 
{ 
    return ((10)*(20)); 
} 

這對你只是一個數據點。

+2

正如它應該那樣 - 預處理器的使用只是文本替換。儘管如此,編譯器本身通常會在編譯時用常量替換表達式。 –

6

這是一個問題:

  • Q1。 C預處理器可以執行算術嗎?

這是另一種:

  • Q2。 C預處理器能否計算算術表達式,然後將結果「粘貼」到我的代碼中,而不是將原始表達式「粘貼」到代碼中?

Q1的答案是肯定的。 Q2的答案是否定的。這兩個事實都可以用以下文件說明: 以下文件:

foo。Ç

#define EXPR ((1 + 2) * 3) 
#if EXPR == 9 
int nine = EXPR; 
#else 
int not_nine = EXPR; 
#endif 

如果我們經過了到C預處理器,或者通過cpp foo.c或 等效gcc -E foo.c,我們看到輸出像:

# 1 "foo.c" 
# 1 "<command-line>" 
# 1 "/usr/include/stdc-predef.h" 1 3 4 
# 30 "/usr/include/stdc-predef.h" 3 4 
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4 
# 31 "/usr/include/stdc-predef.h" 2 3 4 
# 1 "<command-line>" 2 
# 1 "foo.c" 


int nine = ((1 + 2) * 3); 

預處理器保留限定int nine和 線的事實已經刪除了定義not_nine的行,表明它已正確執行 評估#if EXPR == 9所需的算術。

的事實定義的預處理文本int nine = ((1 + 2) * 3); 告訴我們,#define指令導致預處理器,以取代 EXPR與其定義((1 + 2) * 3)與其定義,9的算術值 。

C預處理器除#define之外是否還有其他指令,它具有第二個 效果?第

但是,這並不當然意味着的int nine定義必須包括一個 運行時間計算,因爲編譯器將在編譯時幾乎肯定評價 算術表達式((1 + 2) * 3)與 不斷更換9

我們可以通過檢查 編譯目標文件來了解編譯器如何翻譯源文件。大多數工具鏈將提供類似GNU binutils objdump的協助。如果我編譯foo.c用gcc:

gcc -c -o foo.o foo.c 

,然後調用:

objdump -s foo.o 

看到foo.o的全部內容,我得到:

foo.o:  file format elf64-x86-64 

Contents of section .data: 
0000 09000000        ....    
Contents of section .comment: 
0000 00474343 3a202855 62756e74 752f4c69 .GCC: (Ubuntu/Li 
0010 6e61726f 20342e38 2e312d31 30756275 naro 4.8.1-10ubu 
0020 6e747539 2920342e 382e3100   ntu9) 4.8.1. 

而且還有所希望的在.data部分硬編碼爲9

注意預處理器的運算能力被限制整數算術

+0

查看'-S' gcc選項,它可以生成彙編代碼。你可能會覺得更容易解釋。 – rici

+1

爲了記錄,預處理器*是* [[完全能夠用宏發射算術'9]],但支持代碼需要做的很荒唐。 – Leushenko

+0

@Leushenko strewth!:) –

1

是的,你可以做使用預處理算法,但它需要大量的工作。閱讀this page here,演示如何創建增量計數器和一個while循環。因此,與您可以創建另外:

#define ADD_PRED(x, y) y 
#define ADD_OP(x, y) INC(x), DEC(y) 
#define ADD(x, y) WHILE(ADD_PRED, ADD_OP, x, y) 

EVAL(ADD(1, 2)) // Expands to 3 

所以重用ADD宏,那麼你可以創建一個MUL宏是這樣的:

#define MUL_PRED(r, x, y) y 
#define MUL_OP(r, x, y) ADD(r, x), x, DEC(y) 
#define MUL_FINAL(r, x, y) r 
#define MUL(x, y) MUL_FINAL(WHILE(MUL_PRED, MUL_OP, 0, x, y)) 

EVAL(MUL(2, 3)) // Expands to 6 

司和減法可以建在一個類似的方式。

相關問題