精华内容
下载资源
问答
  • 要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。
  • 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。
  • C语言宏定义用法大全

    2018-06-11 22:12:36
    关于C语言宏定义的用法,作了一个总结,除了常用宏定义外,还有类似函数的宏的用法
  • 内联函数本质上是两不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline
  • C语言宏定义、宏函数、内置宏与常用宏

    万次阅读 多人点赞 2018-09-30 17:48:43
    C语言(C++)特有的两把双刃剑指针和宏定义/宏函数使得C语言在底层开发中披荆斩棘、无所不能。这两概念涉及范围比较广,其分支点也比较多,可谓星罗棋布,但这每颗星都足以照亮C语言因其开发周期、可维护性、可...

    前言:

    在C语言中,变量类型、循环控制、基础语法等与其他高级语言基本无异;而C语言(C++)特有的两把双刃剑指针宏定义/宏函数使得C语言在底层开发中披荆斩棘、无所不能。这两个概念涉及范围比较广,其分支点也比较多,可谓星罗棋布,但这每颗星都足以照亮C语言因其开发周期、可维护性、可移植性等问题而显的黯淡的天空,使得这门语言灵活多变、操作犀利,令人难以揣摩却也深深着迷。

    首先,C的第一把双刃剑:指针,这也是所有学C的人,最先会接触、最多接触也最无法避免、也是最为之魂牵梦萦茶饭不思的概念;包括一级指针、二级指针、数组指针、指针数组、函数指针、甚至函数指针数组、函数指针数组指针等,怪异称呼说不尽道不清,指东指西、指其所想指,所能指、所不能指。尤其是函数指针、以及函数指针数组等在C的高级特性中(一般是用来进行适配层函数挂载,驱动分发)时常会被用到。

    而宏则是更为锋利的一把双刃剑,由于疏于习练,至今尚未参透其中奥秘。今天且稍作总结,记录学历过程之烦恼万千与趣味无穷。

    关于宏的内容大部分摘自:C语言宏定义,内置宏,FILE,LINE,## 用法

    一、下面列举一些成熟软件中常用的宏定义:

    1,防止一个头文件被重复包含

    #ifndef COMDEF_H
    #define COMDEF_H
    
    //头文件内容 …
    #endif
    

    2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。

    typedef  unsigned long int  uint32;      	/* Unsigned 32 bit value */
    

    3,得到指定地址上的一个字节或字

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

    4,求最大值和最小值

    #define  MAX( x, y )  ( ((x) > (y)) ? (x) : (y) )
    #define  MIN( x, y )  ( ((x) < (y)) ? (x) : (y) )
    

    5,得到一个field在结构体(struct)中的偏移量

    #define FPOS( type, field )   ( (dword) &(( type *) 0)-> field )
    

    6,得到一个结构体中field所占用的字节数

    #define FSIZ( type, field ) sizeof( ((type *) 0)->field )
    

    7,按照LSB格式把两个字节转化为一个word

    #define  FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
    

    8,按照LSB格式把一个word转化为两个字节

    #define  FLOPW( ray, val ) \
    (ray)[0] = ((val) / 256); \
    (ray)[1] = ((val) & 0xFF)
    

    9,得到一个变量的地址(word宽度)

    #define  B_PTR( var )  ( (byte *) (void *) &(var) )
    #define  W_PTR( var )  ( (word *) (void *) &(var) )
    

    10,得到一个字的高位和低位字节

    #define  WORD_LO(xxx)  ((byte) ((word)(var) & 255))
    #define  WORD_HI(xxx)  ((byte) ((word)(var) >> 8))
    

    11,返回一个比X大的最接近的8的倍数

    #define RND8( x )       ((((x) + 7) / 8 ) * 8 )
    

    12,将一个字母转换为大写

    #define  UPCASE( ch ) ( ((ch) >= ’a' && (ch) <= ’z') ? ((ch) - 0×20) : (ch) )
    

    13,判断字符是不是10进值的数字

    #define  DECCHK( ch ) ((ch) >= ’0′ && (ch) <= ’9′)
    

    14,判断字符是不是16进值的数字

    #define  HEXCHK( ch ) \
    (((ch) >= ’0′ && (ch) <= ’9′) || \
    ((ch) >= ’A' && (ch) <= ’F') || \
    ((ch) >= ’a' && (ch) <= ’f') )
    

    15,防止溢出的一个方法

    #define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val))
    

    16,返回数组元素的个数

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

    17,对于IO空间映射在存储空间的结构,输入输出处理

    #define inp(port)         (*((volatile byte *) (port)))
    #define inpw(port)        (*((volatile word *) (port)))
    #define inpdw(port)       (*((volatile dword *)(port)))
    
    #define outp(port, val)   (*((volatile byte *) (port)) = ((byte) (val)))
    #define outpw(port, val)  (*((volatile word *) (port)) = ((word) (val)))
    #define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
    

    二、使用一些内置宏跟踪调试:

    ANSI标准定义了几个个预定义的宏名。它们包括但不止于:

    __LINE__
    __FILE__
    __DATE__
    __TIME__
    __STDC__
    

    注: 常用的还有__FUNCTION__等【非标准】,详细信息可查看:Predefined Macros,如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序 也许还提供其它预定义的宏名。可以定义宏,例如:当定义了_DEBUG,输出数据信息和所在文件所在行

    #ifdef _DEBUG
    #define DEBUGMSG(msg,date) printf(msg);printf("%d%d%d", date, __LINE__, __FILE__)
    #else
    #define DEBUGMSG(msg,date)
    #endif
    

    三、宏定义防止使用时错误:

    用小括号包含。

    //例如:
    #define ADD(a,b) (a+b)
    

    用do{}while(0)语句包含多语句防止错误(注意while(0)后无分号).

    //例如:
    #difne DO(a,b) a+b; a++;
    //应写成:
    #difne DO(a,b) do{a+b; a++;}while(0)
    

    为什么需要do{…}while(0)形式?大致有以下几个原因:

    1),空的宏定义避免warning:
    #define foo() do{}while(0)

    2),存在一个独立的block,可以用来进行重复性变量定义,进行比较复杂的实现。

    3),如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现:

    #define foo(x)
    action1();
    action2();
    //在以下情况下:
    if(NULL == pPointer)
        foo();
    //就会出现action2必然被执行的情况,而这显然不是程序设计的目的。
    

    4),以上的第3种情况用单独的{}也可以实现,但是为什么一定要一个do{}while(0)呢,看以下代码:

    #define switch(x,y) {int tmp; tmp=x;x=y;y=tmp;}
    if(x>y)
       switch(x,y);
    else        //error, parse error before else
       otheraction();
    

    在把宏引入代码中,会多出一个分号,从而会报错。使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低,【但是并非所有情况都用这种形式,有些情况不需要,有些情况则不能够够】。

    四、宏中#和##的用法

    1、一般用法
    我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.例如:

    #include<cstdio>
    #include<climits>
    using namespace std;
    
    #define STR(s)     #s
    #define CONS(a,b)  int(a##e##b)
    
    int main()
    {
    	/* 输出字符串vck */ 
    	printf(STR(vck));						
    	
    	/* 2e3 输出:2000 */ 
    	printf("%d\n", CONS(2,3));					
    	return 0;
    }
    

    2、当宏参数是另一个宏的时候

    需要注意的是凡宏定义里有用###的地方宏参数是不会再展开.

    (1)、没有’#'和’##’的情况

    #define TOW      (2)
    #define MUL(a,b) (a*b)
    
    printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
    

    这行的宏会被展开为:
    printf("%d*%d=%d\n", (2), (2), ((2)*(2)));
    MUL里的参数TOW会被展开为(2).

    (2)、当有’#'或’##’的时候

    #define A          (2)
    #define STR(s)     #s
    #define CONS(a,b)  int(a##e##b)
    
    printf("int max: %sn",  STR(INT_MAX));    // INT_MAX #include<climits>
    printf("%s\n", CONS(A, A));               // compile error
    

    第一个printf()这行会被展开为:
    printf(“int max: %s\n”, #INT_MAX);
    第二个printf()则是:
    printf("%s\n", int(AeA)); //编译错误

    INT_MAXA都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏;加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.

    #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)       		// 转换宏
    

    printf(“int max: %s\n”, STR(INT_MAX));
    输出为: int max: 0x7fffffff
    STR(INT_MAX) –> _STR(0x7fffffff) 然后再转换成字符串;

    printf("%d\n", CONS(A, A));
    输出为:200
    CONS(A, A) –> _CONS((2), (2)) –> int((2)e(2))

    (3)、’#'和’##’的一些应用特例:

    ①、合并匿名变量名,例:

    #define  __ANONYMOUS1(type, var, line)  type  var##line
    #define  _ANONYMOUS0(type, line)  __ANONYMOUS1(type, _anonymous, line)
    #define  ANONYMOUS(type)  _ANONYMOUS0(type, __LINE__)
    
    ANONYMOUS(static int);
    //即: 
    static int _anonymous70;  	//70表示该行行号;
    

    ①第一层:ANONYMOUS(static int); –> __ANONYMOUS0(static int, LINE);
    ②第二层:–> ___ANONYMOUS1(static int, _anonymous, 70);
    ③第三层:–> static int _anonymous70;
    即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;

    ②、填充结构

    #define  FILL(a)   {a, #a}
    
    enum IDD{OPEN, CLOSE};
    typedef struct MSG{
    	IDD id;
    	const char * msg;
    }MSG;
    
    MSG _msg[] = {
    	FILL(OPEN), 
    	FILL(CLOSE)
    };
    //相当于:
    MSG _msg[] = {
    	{OPEN, “OPEN”},
    	{CLOSE, ”CLOSE“}
    };
    

    ③、记录文件名

    #define  _GET_FILE_NAME(f)   #f
    #define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)
    static char  FILE_NAME[] = GET_FILE_NAME(__FILE__);
    

    ④、得到一个数值类型所对应的字符串缓冲大小

    #define  _TYPE_BUF_SIZE(type)  sizeof #type
    #define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type)
    char  buf[TYPE_BUF_SIZE(INT_MAX)];
    

    char buf[_TYPE_BUF_SIZE(“0x7fffffff”)];
    char buf[sizeof “0x7fffffff”];
    这里相当于:
    char buf[11];

    五、__VA_ARGS__##__VA_ARGS__

    __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。##__VA_ARGS__ 宏,在__VA_ARGS__前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的逗号去掉的作用,否则会编译出错。(摘自:#、##、__VA_ARGS__和##__VA_ARGS__的作用

    使用例如:Linux C实现文件拷贝可变色进度条显示

    展开全文
  • 要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。  在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏...

        要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。

      在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。

       宏定义中允许包含两行以上命令的情形,此时必须在最右边加上"\"且该行"\"后不能再有任何字符,连注释部分都不能有,下面的每行最后的一定要是"\","\"后面加一个空格都会报错,更不能跟注释。

      我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:

    #define MAX( a, b) ( (a) > (b) (a) : (b) )
    

      其次,把它用函数来实现:

    int max( int a, int b)
    
    {
    
    return (a > b a : b)
    
    }
    

      很显然,我们不会选择用函数来完成这个任务,原因有两个:首先,函数调用会带来额外的开销,它需要开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈。这种开销不仅会降低代码效率,而且代码量也会大大增加,而使用宏定义则在代码规模和速度方面都比函数更胜一筹;其次,函数的参数必须被声明为一种特定的类型,所以它只能在类型合适的表达式上使用,我们如果要比较两个浮点型的大小,就不得不再写一个专门针对浮点型的比较函数。反之,上面的那个宏定义可以用于整形、长整形、单浮点型、双浮点型以及其他任何可以用“>”操作符比较值大小的类型,也就是说,宏是与类型无关的。

      和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。

      还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。

      看下面的例子:

    #define MALLOC(n, type) \
    
    ((type *) malloc((n)* sizeof(type)))
    

      利用这个宏,我们就可以为任何类型分配一段我们指定的空间大小,并返回指向这段空间的指针。我们可以观察一下这个宏确切的工作过程:

    int *ptr;
    
    ptr = MALLOC ( 5, int );
    

      将这宏展开以后的结果:

    ptr = (int *) malloc ( (5) * sizeof(int) );
    

      这个例子是宏定义的经典应用之一,完成了函数不能完成的功能,但是宏定义也不能滥用,通常,如果相同的代码需要出现在程序的几个地方,更好的方法是把它实现为一个函数。

      下面总结和宏和函数的不同之处,以供大家写代码时使用,这段总结摘自《C和指针》一书。

    【转】C语言中DEFINE简介及多行宏定义

    EXample

    define的单行定义

    #define max(a,b) (a>b?a:b)
    

    define的多行定义

    define可以替代多行的代码,例如MFC中的宏定义

    #define   MACRO(arg1,   arg2)   do   {   \ 
       \ 
    stmt1;   \ 
    stmt2;   \ 
       \ 
    }   while(0)
    

    关键是要在每一个换行的时候加上一个 "\ "

    //宏定义写出swap(x,y)交换函数
    #define swap(x, y)\
    x = x + y;\
    y = x - y;\
    x = x - y;
    
    自己写的一个小例子: 
    // 不能加 * ,因为指针也是一种类型
    
    #define  SORT( a,  n)\
    
    {\
    
        int i, j;\
    
        int *t = MALLOC(1,int);\
    
        for(i=0; i<n-1; i++)\
    
        {\
    
            for(j=0; j<n-1-i; j++)\
    
            {\
    
                if(*(a+j) > *(a+j+1))\
    
                {\
    
                    *t = *(a+j);\
    
                    *(a+j) = *(a+j+1);\
    
                    *(a+j+1) = *t;\
    
                }\
    
            }\
    
        }\
    
    }
    
    
    
    int main(int argc, const char * argv[])
    
    {
    
        int a=10, b= 120;
    
    
    
        int data[]={3,200,5};
    
        //swap(&a, &b);
    
        
    
       // sort(data, 3);     //和队列一样:会依据实参自动识别类型
    
        
    
        SORT(data, 3);     //会主动用实参代替形参识别类型
    
        
    
        for(int i=0;i<3;i++)
    
        cout << data[i]  << endl;
    
        
    
        
    
        //printf("%d   %d", a, b);
    
        return 0;
    
    展开全文
  • C语言宏定义函数

    万次阅读 多人点赞 2019-03-18 11:40:46
    通过一个比较函数的例子来说明宏函数和普通函数的区别: 宏函数形式: #define MAX( a, b) ( (a) &gt; (b) (a) : (b) ) //这里为什么有这么多括号,后面会讲 普通函数形式: int max(int a, int b) { ...

    通过一个比较函数的例子来说明宏函数和普通函数的区别:

    宏函数形式:

    #define MAX( a, b) ( (a) > (b) (a) : (b) ) //这里为什么有这么多括号,后面会讲

    普通函数形式:

    int max(int a, int b)
    {
         return (a > b a : b)
    }

    宏函数

    优点:节省空间(给形参节省)

    缺点:浪费时间(主要浪费在编译时);没有语法检查,不安全。

    普通函数

    优点:有语法检查

    缺点:浪费空间。


    注意宏函数在调用时只是对函数中的变量做简单的替换,注意这里的替换真的是替换,非常死板的那种!!!

    可以看一下下面的例子:

    #define SQUARE_SUM(x,y) x*x+y*y
    #include <stdio.h>
    
    int main()
    {
        int i = 1,j = 2,k ;
        k = SQUARE_SUM(i+1,j);
        printf("%d",k);
        return 0;
    }

    很多人可能会这样算:2*2+2*2=8,这样其实是错误的。

    看一下程序运行的结果:

    原因是程序只是做了替换,也就是1+1*1+1+2*2=7

    现在知道为什么要在宏函数定义时加这么多括号了吧 (= =)

    想达到结果为8的效果应该这样写:

    #define SQUARE_SUM(x,y) (x)*(x)+(y)*(y) //注意这里的括号!!
    #include <stdio.h>
    
    int main()
    {
        int i = 1,j = 2,k ;
        k = SQUARE_SUM(i+1,j);
        printf("%d",k);
        return 0;
    }

    运行结果:

    OK! 大功告成!

    展开全文
  • 尽管函数宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等系列工作,因此那些简短并且被频繁调用的函数经常用函数宏定义来代替实现...

    http://www.jb51.net/article/41869.htm

    尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现

    在C及C++语言中允许用一个标识符来表示一个字符串,称为宏,该字符串可以是常数、表达式、格式串等。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。若字符串是表达式,我们称之为函数式宏定义,那函数式宏定义与普通函数有什么区别呢?

    我们以下面两行代码为例,展开描述:
    函数式宏定义:#define MAX(a,b) ((a)>(b)?(a):(b))
    普通函数 :MAX(a,b) { return a>b?a:b;}

    (1)函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。

    (2)调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。

    如果MAX是个普通函数,那么它的函数体return a > b ? a : b; 要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。

    (3)函数式宏定义要注意格式,尤其是括号。

    如果上面的函数式宏定义写成 #define MAX(a, b) (a>b?a:b),省去内层括号,则宏展开就成了k = (i&0x0f>j&0x0f?i&0x0f:j&0x0f),运算的优先级就错了。同样道理,这个宏定义的外层括号也是不能省的。若函数中是宏替换为 ++MAX(a,b),则宏展开就成了 ++(a)>(b)?(a):(b),运算优先级也是错了。

    (4)若函数参数为表达式,则普通函数的调用与函数式宏定义的替换过程是不一样的。

    普通函数调用时先求实参表达式的值再传给形参,如果实参表达式有Side Effect,那么这些SideEffect只发生一次。例如MAX(++a, ++b),如果MAX是普通函数,a和b只增加一次。但如果MAX函数式宏定义,则要展开成k = ((++a)>(++b)?(++a):(++b)),a和b就不一定是增加一次还是两次了。所以若参数是表达式,替换函数式宏定义时一定要仔细看好。

    (5)函数式宏定义往往会导致较低的代码执行效率。

    看下面一段代码:

    复制代码 代码如下:

    int a[]={9,3,5,2,1,0,8,7,6,4};
    int max(n)
    {
        return n==0?a[0]:MAX(a[n],max(n-1));
    }

    int main()
    {
        max(9);
        return 0;
    }


    若是普通函数,则通过递归,可取的最大值,时间复杂度为O(n)。但若是函数式宏定义,则宏展开为( a[n]>max(n-1)?a[n]:max(n-1) ),其中max(n-1)被调用了两遍,这样依此递归下去,时间复杂度会很高。

    尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。


    http://blog.sina.com.cn/s/blog_861912cd0100tc94.html

    要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。

      在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。

      我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:

      #define MAX( a, b) ( (a) > (b) (a) : (b) )

      其次,把它用函数来实现:

      int max( int a, int b)

      {

      return (a > b a : b)

      }

      很显然,我们不会选择用函数来完成这个任务,原因有两个:首先,函数调用会带来额外的开销,它需要开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈。这种开销不仅会降低代码效率,而且代码量也会大大增加,而使用宏定义则在代码规模和速度方面都比函数更胜一筹;其次,函数的参数必须被声明为一种特定的类型,所以它只能在类型合适的表达式上使用,我们如果要比较两个浮点型的大小,就不得不再写一个专门针对浮点型的比较函数。反之,上面的那个宏定义可以用于整形、长整形、单浮点型、双浮点型以及其他任何可以用“>”操作符比较值大小的类型,也就是说,宏是与类型无关的。

      和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。

      还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。

      看下面的例子:

      #define MALLOC(n, type) \

      ( (type *) malloc((n)* sizeof(type)))

      利用这个宏,我们就可以为任何类型分配一段我们指定的空间大小,并返回指向这段空间的指针。我们可以观察一下这个宏确切的工作过程:

      int *ptr;

      ptr = MALLOC ( 5, int );

      将这宏展开以后的结果:

      ptr = (int *) malloc ( (5) * sizeof(int) );

      这个例子是宏定义的经典应用之一,完成了函数不能完成的功能,但是宏定义也不能滥用,通常,如果相同的代码需要出现在程序的几个地方,更好的方法是把它实现为一个函数。

      下面总结和宏和函数的不同之处,以供大家写代码时使用,这段总结摘自《C和指针》一书。


     


    example:

    define的单行定义

    #define maxi(a,b) (a>;b?a:b)
    define的多行定义

    define可以替代多行的代码,例如MFC中的宏定义(非常的经典,虽然让人看了恶心)

    #define     MACRO(arg1,     arg2)     do     {     \
         \
    stmt1;     \
    stmt2;     \
         \
       while(0)   
    关键是要在每一个换行的时候加上一个 "\ "


    //宏定义写出swap(x,y)交换函数
    #define swap(x, y)\
    x = x + y;\
    y = x - y;\
    x = x - y;


    zigbee里多行define有如下例子

    #define FillAndSendTxOptions( TRANSSEQ, ADDR, ID, LEN, TxO ) { \
    afStatus_t stat;                                                                       \
    ZDP_TxOptions = (TxO);                                                           \
    stat = fillAndSend( (TRANSSEQ), (ADDR), (ID), (LEN) );                   \
    ZDP_TxOptions = AF_TX_OPTIONS_NONE;                                 \
    return stat;                                                                               \
    }

    展开全文
  • 今天来说说。...下面通过一个小程序加以说明。#include#include#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)int main(int argc, char* argv[]){OUTSCREEN("Hello World!n%s", "__This is...
  • C语言宏定义

    2020-12-29 11:24:09
    C语言宏定义C语言既具有高级语言的功能,又具有低级语言的许多功能。那么大家知道C语言宏定义是怎样的呢?下面一起来看看!宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。先看一个例子:#include#...
  • 关于C语言宏定义#define 最常用的莫过于通过宏定义定义常数了,例如#define MAX 1000 通过宏定义程序中需要的常量,方便维护被多次引用的变量,并且宏替换在预处理阶段完成,程序运行是被替换为确定的值。...
  • 较大的C语言项目都会用大量的宏定义来组织代码,比较经典的代码就是Linux Kernel的头文件中用的宏定义。看起来宏展开就是做替换而已,其实里面有比较复杂的规则,有关宏展开的语法规则此小结力图整理的比较全面。...
  • 同样道理,这个宏定义的外层括号也是不能省的。若函数中是宏替换为 ++MAX(a,b),则宏展开就成了 ++(a)>(b)?(a):(b),运算优先级也是错了。 (3)宏函数往往会导致较低的代码执行效率。 int a[]={9,3,5,2,1,0,8,7,6,...
  • C语言_宏定义

    万次阅读 多人点赞 2019-02-02 00:20:03
      编译一个C语言程序的第一步骤就是预处理阶段,这一阶段就是发挥作用的阶段。C预处理器在源代码编译之前对其进行一些文本性质的操作,主要任务包括删除注释、插入被#include进来的文件内容、定义和替换由#...
  • C语言宏定义(常用宏定义)

    千次阅读 多人点赞 2018-11-07 12:50:10
    C语言常用宏定义常用宏定义数值相关的宏定义字符相关的宏定义byte相关的宏定义bit相关的宏定义数组与结构体相关的宏定义对齐的宏定义 常用宏定义 数值相关的宏定义 闰年的判断 ,年份可以整除4并且不能整除...
  • C语言宏定义讲解

    千次阅读 多人点赞 2019-04-28 21:13:17
    详细讲解了C语言的两大宏定义
  • 再谈C语言宏定义

    千次阅读 2020-05-17 23:47:56
    再谈C语言宏定义 文章目录再谈C语言宏定义简单的宏定义带参数宏定义宏定义中的#和##运算符#运算符##运算符删除宏定义常用预定义宏 简单的宏定义 简单宏定义格式 [关键字] [标识符] [替换列表] 关键字 #define ...
  • C语言位操作宏定义函数

    万次阅读 2021-06-18 15:48:54
    我们在写C语言时,经常需要用到位操作,但是每次自己使用逻辑运算符进行操作的时候,很费脑子,试试下面几个宏定义吧: #define GET_BIT(value,bit) ((value)&(1<<(bit))) //读取指定位 #define CPL_BIT...
  • C语言基础--宏函数

    千次阅读 2020-06-07 15:43:45
    C语言基础–宏函数 1. 函数和数据类型 函数(宏函数)和函数类比会更加灵活,我们通过两例子来看一下。 函数 #include <stdio.h> int sqr_int(int x) { return x*x; } double sqr_double(double x) { ...
  • 宏定义中的参数称为形式参数,在宏调用中的参数称为实际 参数。 对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。 带参宏定义的一般形式为: #define 宏名(形参列表) 字符串 在字符串中含有各个...
  • C语言 宏定义、数组

    千次阅读 2020-09-18 20:14:50
    1)宏定义就是用一个标识符来表示一个字符串,如果后面代码中出现了该标识符,就全部替换成指定的字符串; 2)定义格式: #define 宏名 字符串 宏名是一种标识符,遵从宏定义命名规则;字符串可以是数字,表达式,if...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,817
精华内容 39,926
关键字:

c语言宏定义一个函数

c语言 订阅