C語言宏定義,Linux中的一些宏定義


下面列舉了一些常見的宏寫法:

#include <stdio.h>

#include <stdlib.h>

#define byte char

#define word short

//得到指定地址上的一個字節或字

#define MEM_B( x ) ( *( (byte *) (x) ) )

#define MEM_WORD( x ) ( *( (int *) (x) ))

//得到一個field在結構體(struct)中的偏移量

#define FPOS(type,member) ((size_t) &((type *)0 )->member)

//得到一個結構體中field所占用的字節數

#define FSIZE(type,member) (sizeof((type *)0)->member)

 

//得到一個字的高位和低位字節

#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))

#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))

 

#define RND8( x ) ((((x) + 7) / 8 ) * 8 ) // 返回 >=x 的8的倍數

 

#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )

 

#define DECCHK( c ) ((c) >= 0 && (c) <= 9) //判斷是否是10以內的數

 

#define HEXCHK( c ) ( ((c) >= 0 && (c) <= 9) ||\

                     ((c) >= 'A' && (c) <= 'F') ||\

                     ((c) >= 'a' && (c) <= 'f') )  //判斷一個符號是不是16進制字符

 

#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val)) //判斷是否會溢出

 

#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )

 

struct A

{

  int  a;

  int  b;

  long long c;

};

 
int main()
{

    struct A *p = (struct A *)malloc(sizeof(struct A));

 

    char cc[2] = {'1','2'};

    short a = 256;

    int aa =0x7fffffff;

    int bb = aa;

 

    p->a = 0x0000000f;

    p->b = 2;

    p->c = 10;

 
    printf("MEM_B: %d \n",MEM_B(p));//打印結果為15,可見x86是小端機

    printf("MEM_WORD: %d \n",MEM_WORD(p));// 15

    printf("FPOS: %d\n",FPOS(struct A,b));//4

    printf("FSIZE: %d\n",FSIZE(struct A, c));//8

 
    printf("WORD_HI: %d WORD_LO: %d\n",WORD_HI(a),WORD_LO(a));//a = 256 1_0000_0000

    //WORD_HI: 1 WORD_LO: 0

    printf("RND8: %d\n",RND8(10)); //16

    printf("UPCASE: %c\n",UPCASE('a'));// A

    printf("DECCHK: %d %d\n",DECCHK(9),DECCHK(10));//1 0

    printf("HEXCHK: %d %d %d\n",HEXCHK(3),HEXCHK('f'),HEXCHK('G'));

 
    printf("INC_SAT: %d %d\n",INC_SAT(aa),INC_SAT(aa) - bb);//2147483647 0

    printf("ARR_SIZE: %d \n",ARR_SIZE(cc));

 
    return 0;

}

 

我們使用#把宏參數變為一個字符串,用##把兩個宏參數貼合在一起。

當宏參數是另一個宏的時候需要注意的是凡宏定義里有用''#''或''##''的地方宏參數是不會再展開。

 

#include<stdio.h>

#include<limits.h>

 

#define A 2

#define _STR(s) #s

#define STR(s) _STR(s) // 轉換宏,如果不使用轉換宏則宏參數不會被展開

#define _CONS(a,b) (int)(a##e##b)

#define CONS(a,b) _CONS(a,b) // 轉換宏

#define TOW (2)

#define MUL(a,b) (a*b)


int main()

{

    printf(STR(vck)); // 輸出字符串"vck"

    printf("\n%d \n", _CONS(2,3)); // 2e3 輸出:2000

    printf("%d * %d = %d\n", TOW, TOW, MUL(TOW,TOW));

    //INT_MAX 作為一個宏不會在STR中被展開

    printf("int max: %s %d\n", STR(INT_MAX),INT_MAX);//INT_MAX, 2147483647

    printf("%d\n", CONS(A, A));//200

    return 0;

}

 

Linux內核中的一些宏定義(前面list_head文章中講過的就不說了,比如container_of之類的):

常用的宏:

__init,標記內核啟動時所用的初始化代碼,內核啟動完成后就不再使用。其所修飾的內容被放到.init.text section中:

#define __init __section(.init.text) __cold notrace

__exit,標記模塊退出代碼,對非模塊無效

__initdata,標記內核啟動時所用的初始化數據結構,內核啟動完成后不再使用。其所修飾的內容被放到.init.data section中:

#define __initdata __section(.init.data)

#define __exit_call  __used __section(.exitcall.exit)

__devinit,標記設備初始化所用的代碼

__devinitdata,標記設備初始化所用的數據結構

__devexit,標記設備移除時所用的代碼

xxx_initcall,7個級別的初始化函數

其典型用法如下:

static int __init xxx_drv_init(void)

{

      return pci_register_driver(&xxx_driver);

}

根據上面的定義與用法,xxx_drv_init()函數將會被link到.init.text段。

之所以加入這樣的宏,原因有2:

1.一部分內核初始化機制依賴與它。如kernel將初始化要執行的init函數,分為7個級別,core_initcall, postcore_initcall, arch_initcall, subsys_initcall, fs_iitcall, device_initcall, late_initcall。這7個級別優先級遞減,即先執行core_initcall, 最后執行late_initcall。

2.提高系統效率。初始化代碼的特點是,在系統啟動時運行,且一旦運行后馬上推出內存,不再占用內存。

 

driver中的使用:

module_init, module_exit函數所調用的函數,需要分別用__init和__exit來標記 pci_driver數據結構不需要標記

probe和remove函數用__devinit和__devexit來標記

如果remove使用__devexit標記,則在pci_drvier結構中要用__devexit_p(remove)來引用remove函數 。

Linux內核中定義了很多的宏,在不斷學習的過程中需要不斷的積累。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM