1. 程式人生 > >c語言學習--巨集定義、條件編譯等

c語言學習--巨集定義、條件編譯等

1. 防止一個頭檔案被重複包含 

  1. #ifndef COMDEF_H 
  2. #define COMDEF_H 
  3. //標頭檔案內容 
  4. #endif 
2. 重新定義一些型別,防止由於各種平臺和編譯器的不同,而產生的型別位元組數差異,方便移植。 
  1. typedef  unsigned char      boolean;     /* Boolean value type. */
  2. typedef  unsigned longint  uint32;      /* Unsigned 32 bit value */
  3. typedef  unsigned short
         uint16;      /* Unsigned 16 bit value */
  4. typedef  unsigned char      uint8;       /* Unsigned 8  bit value */
  5. typedefsignedlongint    int32;       /* Signed 32 bit value */
  6. typedefsignedshort       int16;       /* Signed 16 bit value */
  7. typedefsignedchar        int8;        /* Signed 8  bit value */
3. 得到指定地址上的一個位元組或字 

  1. #define  MEM_B( x )  ( *( (int8 *) (x) ) ) 
  2. #define  MEM_W( x )  ( *( (uint16 *) (x) ) ) 
4. 求最大值和最小值 
    會存在Duplication of Side Effects問題。這裡的Side Effect是指巨集在展開的時候對其引數可能進行多次Evaluation(也就是取值),但是如果這個巨集引數是一個函式,那麼就有可能被呼叫多次從而達到不一致的結果,甚至會發生更嚴重的錯誤。比如:
  1. #define  MAX( x, y ) ( ((x) > (y)) ? (x) : (y) ) 
  2. #define  MIN( x, y ) ( ((x) < (y)) ? (x) : (y) ) 
  3. c = min(a,foo(b));  
這時foo()函式就被呼叫了兩次。為了解決這個潛在的問題,我們應當這樣寫min(X,Y)這個巨集:
  1. #define min(X,Y) ({\
  2. typeof (X) x_ = (X);\  
  3. typeof (Y) y_ = (Y);\  
  4. (x_ < y_) ? x_ : y_; })  
({...})的作用是將內部的幾條語句中最後一條的值返回,它也允許在內部宣告變數(因為它通過大括號組成了一個區域性Scope)

5,得到一個field在結構體(struct)中的偏移量 
  1. #define FPOS( type, field ) ( (dword) &(( type *) 0)-> field )

6,得到一個結構體中field所佔用的位元組數 
  1. #define FSIZ( type, field ) sizeof( ((type *) 0)->field ) 

7,按照LSB格式把兩個位元組轉化為一個Word 
  1. #define  FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] ) 

8,按照LSB格式把一個Word轉化為兩個位元組 
  1. #define<span style="white-space:pre">   </span>FLOPW( ray, val ) \ 
  2. <span style="white-space:pre">  </span>(ray)[0] = ((val) / 256); \   
  3. <span style="white-space:pre">  </span>(ray)[1] = ((val) & 0xFF)   

9,得到一個變數的地址(word寬度) 
  1. #define  B_PTR( var )  ( (int8 *) (void *) &(var) ) 
  2. #define  W_PTR( var )  ( (uint16 *) (void *) &(var) ) 

10,得到一個字的高位和低位位元組 
  1. #define  WORD_LO(xxx)  ((byte) ((uint16)(xxx) & 255)) 
  2. #define  WORD_HI(xxx)  ((byte) ((uint16)(xxx) >> 8)) 

11,返回一個比X大的最接近的8的倍數 
  1. #define RND8( x )       ((((x) + 7) / 8 ) * 8 ) 

12,將一個字母轉換為大寫 
  1. #define  UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )

13,判斷字元是不是10進值的數字 
  1. #define  DECCHK( c ) ((c) >= ''0'' && (c) <= ''9'') 

14,判斷字元是不是16進值的數字 
  1. #define  HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||\ 
  2.                        ((c) >= ''A'' && (c) <= ''F'') ||\   
  3.                ((c) >= ''a'' && (c) <= ''f'') )   

15,防止溢位的一個方法 
  1. #define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val)) 

16,返回陣列元素的個數 
  1. #define  ARR_SIZE( a )  ( sizeof( (a) ) / sizeof( (a[0]) ) ) 

17,返回一個無符號數n尾的值

MOD_BY_POWER_OF_TWO(X,n)=X%(2^n) 

  1. #define MOD_BY_POWER_OF_TWO( val, mod_by ) \ 
  2.            ( (dword)(val) & (dword)((mod_by)-1) )   

18,對於IO空間對映在儲存空間的結構,輸入輸出處理 
  1. #define inp(port)         (*((volatile byte *) (port))) 
  2. #define inpw(port)        (*((volatile word *) (port))) 
  3. #define inpdw(port)       (*((volatile dword *)(port))) 
  4. #define outp(port, val)   (*((volatile byte *) (port)) = ((byte) (val))) 
  5. #define outpw(port, val)  (*((volatile word *) (port)) = ((word) (val))) 
  6. #define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val))) 
19. 使用一些巨集跟蹤除錯 
ANSI標準說明了五個預定義的巨集名。它們是: 
_LINE_
_FILE_ 
_DATE_ 
_TIME_ 
_STDC_ 
如果編譯不是標準的,則可能僅支援以上巨集名中的幾個,或根本不支援。記住編譯程式也許還提供其它預定義的巨集名。 
_LINE_標識當前程式碼所在的行號
_FILE_標識程式碼所在的檔名
_DATE_巨集指令含有形式為月/日/年的串,表示原始檔被翻譯到程式碼時的日期。 
原始碼翻譯到目的碼的時間作為串包含在_TIME_中。串形式為時:分:秒。 
如果實現是標準的,則巨集_STDC_含有十進位制常量1。如果它含有任何其它數,則實現是非標準的。 

可以定義巨集,例如: 
當定義了_DEBUG,輸出資料資訊和所在檔案所在行 
  1. #ifdef _DEBUG 
  2. #define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_) 
  3. #else 
  4. #define DEBUGMSG(msg,date) 
  5. #endif 

20. 巨集定義防止使用是錯誤用小括號包含。 
例如:
  1. #define ADD(a,b) (a+b) 
用do{}while(0)語句包含多語句防止錯誤 
例如:
  1. #difne DO(a,b) a+b; a++; 
應用時:
  1. if(...)   
  2. DO(a,b); //產生錯誤 
  3. else
  4. ...  
解決方法: 
  1. #define DO(a,b) do{a+b;a++;}while(0) 

21. 巨集中"#"和"##"的用法
#的功能是將其後面的巨集引數進行字串化操作(Stringfication)。
##被稱為連線符(concatenator),用來將兩個Token連線為一個Token。注意這裡連線的物件是Token就行,而不一定是巨集的變數。
用法: 
  1. 相關推薦

    c語言學習--巨集定義條件編譯

    1. 防止一個頭檔案被重複包含  #ifndef COMDEF_H  #define COMDEF_H  //標頭檔案內容  #endif  2. 重新定義一些型別,防止由於各種平臺和編譯器的不同,而產生的型別位元組數差異,方便移

    C語言詳解(6)巨集定義條件編譯

    巨集定義和條件編譯 一、概述 巨集定義是C語言的預處理功能。巨集定義就是簡單的替換,不作為計算,不也作為表示式。在C語言中作為預處理指令包括:巨集定義、檔案包含、條件編譯。 條件編譯其實就是將if…else…的設計思想引入到預處理功能中,給編譯器使用的。條件編譯時通過

    C語言開關巨集定義學習##__VA_ARGS__

    最近寫c程式,學到一種開關巨集,極大提高程式的控制性: #define __DEBUG #ifdef __DEBUG #define tnfs_print(format, ...) printf (format, ##__VA_ARGS__) #else #define tnfs_print

    C語言(二 運算子條件語句指標)

    C運算子 包括算數運算子,邏輯運算子,關係運算符,位運算子,賦值運算子,其他運算子。 算術運算子 就是加減乘除求餘,自增自減等算術。 邏輯運算子 與:&&,或:||,非:! 關係運算符 等於,大於,小於等組合 位運算子 位與:&,位或:|,位左移<<,位右

    C語言巨集定義define 和型別重新命名typedef

      C語言裡面有兩個不容易區分的語法概念,巨集定義define 和型別重新命名typedef。下面我們來談一下兩者之間的差異。   1.型別重新命名typedef: 關鍵字typedef提供了一種為已定義好的資料型別建立別名的機制,為了建立更簡短的型別名,通常使用type

    C語言巨集定義和函式的取捨

    原文連結:http://www.embedu.org/Column/Column177.htm 要寫好C語言,漂亮的巨集定義是非常重要的。巨集定義可以幫助我們防止出錯,提高程式碼的可移植性和可讀性等。 在軟體開發過程中,經常有一些常用或者通用的功能或者程式碼段,這些功能既可以寫成函式,也可以

    C語言應用巨集定義解決三角形的面積問題

    #include <stdio.h> #include<math.h> #define s(a,b,c) ((0.5)*((a)+(b)+(c))) #define area(s,a,b,c) sqrt((s)*((s)-(a))*((s

    C語言的預處理之"條件編譯"

    C語言的預處理主要有三個方面的內容: 巨集定義 檔案包含 條件編譯     預處理命令以符號"#"開頭。     採用條件編譯,可以減少被編譯的語句,從而減少目標的長度。當條件編譯段比較多時,目標程式長度可以大大減少。 條件編譯主要包括: #if         

    玩兒轉C語言巨集定義(1)

    1、為什麼要有巨集定義?         程式碼中某個特定數值需要參與運算,而且該數值作用於多個地方,當需要對該數值進行修改時,希望只改動一個地方就能實現該數值的全部更新;即便某個數值只用到一次,當修改時也會面臨搜尋閱讀大量程式碼、數值含義不明晰的問題;某些“操作塊”封裝成

    Makefile中用巨集定義進行條件編譯(gcc -D)/在Makefile中進行巨集定義-D

    在原始碼裡面如果這樣是定義的: #ifdef   MACRONAME //可選程式碼 #endif 那在makefile裡面 gcc   -D   MACRONAME=MACRODEF 或者 gcc   -D   MACRONAME  這樣就定義了預處理巨集,編譯的時候可選程式碼就會被編譯進去了。 對於G

    【Object-c基礎】預定義條件編譯,陣列

    1.     預定義:#define 在object-c中,跟C語言一樣都是採用#define才使用,但末尾是沒有分號的; 例子: #define PI 3.14 在之後即可引用,這點在iphone開發中一定每個組建的tag非常好用,並且可以集合放一個定義檔案中。 2.     條件編譯:#ifdef,

    巨集定義條件編譯的用處

       #define     定義巨集     #undef      取消已定義的巨集     巨集定義常量與命令可以避免幻數 在巨集定義命名時候應該儘量清楚表明其用途。 函式型巨集定義的有點:儘管其和真正的函式相比有很多缺點,但只要小心使用還是會顯著提高程式碼的執行效率

    c語言巨集定義缺陷

    |      考慮asert巨集的定義。 |      定義1:#define assert(e) if(!e) _assert_error (__FILE__, __LINE__ ) |                  當 if(x>0 && y>0)    asser

    C語言巨集定義是什麼?

    巨集定義是C提供的三種預處理功能的其中一種,這三種預處理包括:巨集定義、檔案包含、條件編譯 巨集定義又稱為巨集代換、巨集替換,簡稱“巨集”。 格式:#define 識別符號 字串 其中的識別符號就是所謂的符號常量,也稱為“巨集名”。 預處理(預編譯)工作也叫做巨集展開:將巨集名替換為字串。 掌握"巨集"概念的

    C語言__預處理(巨集定義檔案包含條件編譯

    C語言__預處理(巨集定義、檔案包含、條件編譯) 預處理簡單理解     1.C語言在對源程式進行編譯之前,會先對一些特殊的預處理指令作解釋(比如之前使用的#include檔案包含指令),產生一個新的源程式(這個過程稱為編譯預處理),之後再進行通常的編譯

    C語言入門(廿二)之預處理指令巨集條件編譯檔案包含typedefconst

    預處理指令 什麼是預處理指令: 在我們的檔案翻譯成0和1之前做的操作我們稱之為預處理指令。一般情況預處理指令都是以#號開頭的。 巨集定義的格式 不帶引數的巨集定義: #define 巨集名 值 巨集定義的作用:      

    編譯預處理指令:檔案包含指令巨集定義指令條件編譯指令

    編譯預處理指令:檔案包含指令、巨集定義指令、條件編譯指令。“#”開頭,不加分號“;” 1、檔案包含指令:  #include<檔名> 標準目錄下搜尋  #include"檔名" 當前目錄下搜尋,再在標準目錄下搜尋 2、巨集定義指令:  #define 巨集名 巨集文字 //巨集名習慣大寫  #

    程式猿之---C語言細節9(巨集定義max(a,b)巨集定義細節大小端判斷(int&)a什麼意思)

    主要內容:巨集定義、max(a,b)巨集定義細節、大小端判斷、(int&)a什麼意思 #if 1 #include <stdio.h> // 注意空格 #define F (x) ((x) - 1) // F代表後面 #define F(x)

    C語言~巨集操作大全(巨集定義內建巨集__FILE____LINE__##用法)

    當然巨集定義非常重要的,它可以幫助我們防止出錯,提高程式碼的可移植性和可讀性等。 下面列舉一些成熟軟體中常用得巨集定義 1,防止一個頭檔案被重複包含 #ifndef COMDEF_H #define COMDEF_H //標頭檔案內容 … #endif

    C語言巨集定義巨集函式內建巨集與常用巨集

    前言: 在C語言中,變數型別、迴圈控制、基礎語法等與其他高階語言基本無異;而C語言(C++)特有的兩把雙刃劍指標和巨集定義/巨集函式使得C語言在底層開發中披荊斬棘、無所不能。這兩個概念涉及範圍比較廣,其分支點也比較多,可謂星羅棋佈,但這每顆星都足以照亮C語言因其