[英]Learning C #define statement (MACROS)
我目前正在閱讀Stephen G. Kochan的“用C編程”,偶然發現了一個練習(第13章,第5章):
編寫宏
SHIFT
來執行與程序12.3的shift
功能相同的目的。
這是程序12.3 :
unsigned int shift (unsigned int value, int n)
{
if ( n > 0 ) // left shift
value <<= n;
else // right shift
value >>= -n;
return value;
}
這是我當前的代碼:
#include <stdio.h>
#define SHIFT(n) (n) > 0 ? << (n) : >> (-(n))
unsigned int w1 = 0177777u, w2 = 0444u;
printf ("%o\t%o\n" w1 SHIFT(5), w1 << 5);
如果n
為正,則宏中的條件應左移,否則應右移。
因此, printf
兩個參數應該具有相同的值,但是我一直收到編譯器錯誤。
如果我將#define
更改為:
#define SHIFT(n) << n
...該代碼有效,但是我不能右移帶有負號。
SHIFT
的條件版本有什么問題?
讓我們假設這段代碼:
#include <stdio.h>
#define SHIFT(n) (n) > 0 ? << (n) : >> (-(n))
// #define SHIFT(n) << n
int main(int argc, char *argv[])
{
unsigned int w1 = 0177777u, w2 = 0444u;
printf("%o\t%o\n", w1 SHIFT(5), w1 << 5);
}
使用#define SHIFT(n) << n
您的代碼可以按預期工作,因為宏只是文本替換。 因此,編譯器實際上看到了這一點:
printf("%o\t%o\n", w1 << 5, w1 << 5);
代替這個:
printf("%o\t%o\n", w1 SHIFT(5), w1 << 5);
但是隨着#define SHIFT(n) (n) > 0 ? << (n) : >> (-(n))
#define SHIFT(n) (n) > 0 ? << (n) : >> (-(n))
編譯器看到以下內容:
printf("%o\t%o\n", w1 (5) > 0 ? << (5) : >> (-(5)), w1 << 5);
這在語法上是錯誤的,沒有任何意義。
你需要這個:
#include <stdio.h>
#define SHIFT(value, n) ... left as an exercise....
unsigned int shift(unsigned int value, int n)
{
if (n > 0) // left shift
value <<= n;
else // right shift
value >>= -n;
return value;
}
int main(int argc, char *argv[])
{
unsigned int w1 = 0177777u, w2 = 0444u;
printf("%o\t%o\n", SHIFT(w1, 5), shift(w1, 5)); // test case for positive shift value
printf("%o\t%o\n", SHIFT(w1, -5), shift(w1, -5)); // test case for negative shift value
}
首先,請注意,此功能本身是出於學習目的而設計的-絕不會在函數或宏后面隱藏諸如移位之類的基本內容。 這樣做只會降低程序的可讀性。
第一步是修復函數,以便處理n
為零的情況。 主要是,當表達式value >> -0
出現時,我們不想冒險讓編譯器陷入麻煩。 (更重要的是,這還為異國/虛構的補語和符號和幅度系統提供了可移植性。)
inline unsigned int shift (unsigned int value, int n)
{
if (n == 0) // don't shift
;
else if ( n > 0 ) // left shift
value <<= n;
else /* n < 0 */ // right shift
value >>= -n;
return value;
}
( inline
是對編譯器的微優化提示,不要生成任何開銷函數調用代碼。現代編譯器可能不需要。)
然后像函數一樣簡單地實現宏。 在任何類似於函數的宏中,都需要在每個宏參數以及宏本身周圍使用括號。
由於宏沒有return語句,因此必須確保它始終求值到所需的值。 這將要求我們使用條件運算符而不是if-else。 由於?:
不提供if - else if - else
選項,因此它必須是嵌套的?:
表達式。
#define SHIFT(value, n) ( (n)==0 ? (value) : \
((n)>0 ? (value) <<= (n) : \
(value) >>= -(n)) )
這將是避免類似函數的宏的主要原因之一。 除了具有清晰易讀的功能之外,我們還有這種幾乎不可讀的混亂。 笨拙的程序員甚至可能很想把它寫成一條可怕的單行:
#define SHIFT(value, n) ((n)==0?(value):((n)>0?(value)<<=(n):(value)>>=-(n))) // BAD CODE
嘗試這個。
#define SHIFT(n) ((n) > 0 ? << (n) : >> (-(n)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.