zoukankan      html  css  js  c++  java
  • 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内核中定义了很多的宏,在不断学习的过程中需要不断的积累。

  • 相关阅读:
    CSS3 box-shadow(阴影使用)
    缩小窗口时CSS背景图出现右侧空白BUG的解决方法
    html打开个人QQ聊天页面
    帮助你实现元素动画的6款插件
    给出两个颜色,计算中间颜色返回数组
    名字首字母
    自适应网页设计
    tab切换jquery代码
    改变上传文件样式
    剑指offer 面试16题
  • 原文地址:https://www.cnblogs.com/zhuyp1015/p/2537389.html
Copyright © 2011-2022 走看看