`
蒙面考拉
  • 浏览: 155720 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Define学习

 
阅读更多

    宏替换是C/C++系列语言的技术特色,C/C++语言提供了强大的宏替换功能,源代码在进入编译器之前,要先经过一个称为“预处理器”的模块,这个模块将宏根据编译参数和实际编码进行展开,展开后的代码才正式进入编译器,进行词法分析、语法分析等等。

1.使用#define定义的伪函数(函数宏)

    C语言中,#define经常被用来定义伪函数--当避免函数调用的开销带来的效率的重要性被置于安全性之上时。

如下:#define repeated(b, m) (b & m & (b & m)-1) 

这个伪函数的定义是有问题的,如果b,m是一个表达式,b&m的值可能与想象的不同,我们应该给每一个参数加上括号(b)&(m).例如:b*m,如果b=2+3,m=3+5.我们想要的是5*8,但是现实却是2+3*3+5=16.

2.宏常量

    #define MAX 1000

    int array[MAX][MAX]

    在经典著作《Effective C++》中,这种做法却并不提倡,书中更加推荐以const常量来代替宏常量。因为在进行词法分析时,宏的引用已经被其实际内容替换,因此宏名不会出现在符号表中。所以一旦出错,看到的将是一个无意义的数字,比如上文中的1000,而不是一个有意义的名称,如上文中的MAX。而const在符号表中会有自己的位置,因此出错时可以看到更加有意义的错误提示。

3.用于条件编译标识的宏

   #ifndef _HEADER_INC_
   #define _HEADER_INC_
      ……
      ……
   #endif
这种宏标记在头文件中十分常见,用于防止头文件被反复包含。应该养成习惯在每个头文件中都添加这种标记。

4.宏函数

 宏函数的语法有以下特点:
    (1)、如果需要换行,则行末要加反斜杠“\”表示换行。宏函数体的最后一行不加反斜杠。
    (2)、假设有参数ARGU,值为argu,则所有的ARGU被直接替换为argu,#ARGU被认为是字符串,会被替换成"argu"(带引号)。
    (3)、由于宏函数是直接替换,所有一般情况下对宏函数的调用时行末不需要加分号。

宏函数的作用:
1)、避免函数调用,提高程序效率,其实宏是用空间效率换取了时间效率。

2)、#undef指令用于取消前面用#define定义的宏,取消后就可以重新定义宏。

3)、方便程序修改 

实例:

#define SWAP_INT(a, b) do
{\
 int tmp = a; \
 a = b; \
 b = tmp; \
}while(0)

int main( void )
{
 int x = 3, y = 4;
 if( x > y )
 {
  SWAP_INT(x, y);
 }
 return 0;
}

5.关于#和##

#define Conn(x,y) x##y

#define Tochar(x) #@x

#define ToString(x) #x

其中,x##y表示x连接y;int n=Conn(123,456);n=123456.

                                    char *str=Conn("asdf","adf");str="asdfadf".

         #@x表示给x加上单引号; char a=ToChar(1); a='1'.

         #x表示给x加上双引号; char* str=ToString(123321); str="123321".

6.宏与内联函数的关系

  1.内联函数可以调试,而宏定义是不可以调试的。

  2.内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。

  3.内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。

下例:

// 返回 i 的绝对值的宏
#define unsafe(i) \
  ( (i) >= 0 ? (i) : -(i) )
// 返回 i 的绝对值的内联函数
inline
int safe(int i)
{
   return i >= 0 ? i : -i;
}

 

void userCode(int x)
{
   int ans;
 
   ans = unsafe(x++);   // 错误!x 被增加两次
   ans = unsafe(f());   // 危险!f()被调用两次
 
   ans = safe(x++);     // 正确! x 被增加一次
   ans = safe(f());     // 正确! f() 被调用一次
}


  4.和宏不同的,还有内联函数的参数类型被检查,并且被正确地进行必要的转换。

7.经典宏

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 ) \

/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */

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(***) ((byte) ((word)(***) & 255))

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

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

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

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

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

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

#define DECCHK( c ) ((c) >= '0' && (c) <= '9')

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

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

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

((c) >= 'a' && (c) <= 'f') )

15,防止溢出的一个方法

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

16,返回数组元素的个数

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

17,返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)

#define MOD_BY_POWER_OF_TWO( val, mod_by ) \

( (dword)(val) & (dword)((mod_by)-1) )

18,对于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)))

[2005-9-9添加]

19,使用一些宏跟踪调试

A N S I标准说明了五个预定义的宏名。它们是:

_ L I N E _

_ F I L E _

_ D A T E _

_ T I M E _

_ S T D C _

如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序

也许还提供其它预定义的宏名。

_ L I N E __ F I L E _宏指令在有关# l i n e的部分中已讨论,这里讨论其余的宏名。

_ D AT E _宏指令含有形式为月//年的串,表示源文件被翻译到代码时的日期。

源代码翻译到目标代码的时间作为串包含在_ T I M E _中。串形式为时:分:秒。

如果实现是标准的,则宏_ S T D C _含有十进制常量1。如果它含有任何其它数,则实现是

非标准的。

可以定义宏,例如:

当定义了_DEBUG,输出数据信息和所在文件所在行

#ifdef _DEBUG

#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)

#else

#define DEBUGMSG(msg,date)

#endif

20,宏定义防止使用是错误

用小括号包含。

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

do{}while(0)语句包含多语句防止错误

例如:#difne DO(a,b) a+b;\

a++;

应用时:if(.)

DO(a,b); //产生错误

else


分享到:
评论

相关推荐

    define方法和构造函数return对象学习

    不是很清楚把构造函数和类联系起来反正我学的烂大家 看哈 我传的 是盗版

    C语言中const与#define的区别

    本文主要介绍了C语言中const与#define的区别,希望对你的学习有所帮助。

    C语言#define拼接宏定义实现方式

    经过各种尝试,居然成了,特此记录分享一下,方便大家学习。 char A_param=0; char B_pramm=0; //添加宏定义 #define OBJECT A #define DEFINE_(X) X##_param //一次定义 #define DEFINE(X) DEFINE_(X) //再次定义 ...

    傲视群雄的全塔式机壳! 支持18颗硬盘、420水冷!! Fractal Design Define 7 XL深度评测

    【Huan】_傲視群雄的全塔式機殼!_支援18顆硬碟、420水冷!!_Fractal_Design_Define_7_XL深度評

    require.js中的define函数详解

    主要给大家介绍了关于require.js中define函数的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用require.js中的define函数具有一定的参考学习价值,需要的朋友们下面来一起看看吧。

    C语言中define的全部使用方法总结

    学习了这么多年C语言,说实话对宏自以为了如指掌了,没想到看内核代码的时候还是那么吃力,设备驱动代码中有很多这样或者那样的宏定义,各种define,博主在学习的过程中将C语言中所出现的#define定义整理总结了一下...

    C++中const与#define的利弊分析

    C++中不但可以用define定义常量还可以用const定义常量,下面这篇文章主要给大家分析介绍了关于C++中const与#define的利弊,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    Linux c中define的用法小结

    学习了这么多年C语言,说实话对宏自以为了如指掌了,没想到看内核代码的时候还是那么吃力,设备驱动代码中有很多这样或者那样的宏定义,各种define,在学习的过程中将C语言中所出现的#define定义整理总结了一下,供...

    Require.JS中的几种define定义方式示例

    本文主要给大家介绍的是关于Require.JS中define定义方式的相关内容,分享出来供大家参考学习,下面来看看详细的介绍: 定义简单的键值对 define({ color: "black", size: "unisize" }); 定义不带依赖的函数 ...

    eCognition_define教程

    学习eCognition的资料 DataIO API 用户指导手册

    FX1N学习板底层源码

    #define XX00 (GPIOA-&gt;IDR &GPIO;_Pin_0)//PA0 #define XX01 (GPIOA-&gt;IDR &GPIO;_Pin_1)//PA1 #define XX02 (GPIOC-&gt;IDR &GPIO;_Pin_5)//PC5 #define XX03 (GPIOC-&gt;IDR &GPIO;_Pin_6)//PC6 #define XX04 (GPIOC-&gt;IDR...

    自己学习总结的discuz x2笔记

    自己学习总结的discuz x2笔记,相信对你有帮助!

    Linux设备驱动程序学习(2)-调试技术.pdf

    #define KERN_EMERG "&lt;0&gt;" /* system is unusable */ #define KERN_ALERT "&lt;1&gt;" /* action must be taken immediately*/ #define KERN_CRIT "&lt;2&gt;" /* critical conditions */ #define KERN_ERR "&lt;3&gt;" /* error ...

    人工智能大作业基于强化学习求解迷宫问题python实现源码+项目说明+实验报告+可执行文件.zip

    - ui_userDefine.py:“用户自定义”标签页的实现,用户可以输入任意大小的迷宫,自定义火焰周期,训练次数上限。之后进行训练,并以三种不同的速度查看完整的走迷宫结果。 - draw_ui.py: 在ui界面绘制Q表和走迷宫...

    美式台球源码

    美式台球的源代码,效果不错,供学习之用。 #pragma once #define BALL_RADII 13//15 //球的半径 #define MAX_POWER 20.0 //最大力量10.0 #define MAX_MOCHA 0.995 //摩擦力0.995 #define MAX_SECOND_...

    IBM MQ学习笔记试验脚本

    入门级学习笔记,试验用的脚本. runmqsc MX display qmgr display q(SYSTEM*) define ql(QL.A) DESCR('QL.A Test') display QL(QL.A) ALTER QL(QL.A) MAXDEPTH(1000) DISPLAY QL(QL.A) define ql(QL.B) DESCR('QL....

    使用mini-define实现前端代码的模块化管理

    如果你不想花时间学习require.js,也不想翻看长篇的cmd/amd规范,那么这个mini-define就是你不错的选择。如果你之前用过sea.js或require.js那么mini-define更加高效,更加轻量,更加易用。项目地址:github 用法 首先...

Global site tag (gtag.js) - Google Analytics