`
蒙面考拉
  • 浏览: 160257 次
  • 性别: 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_DPM_EROSION.rar_DEFINE DPM EROSION_DPM_UDF EROSION_fluent

    标题中的"DEFINE_DPM_EROSION.rar_DEFINE DPM EROSION_DPM_UDF EROSION_...通过分析提供的源代码 "DEFINE_DPM_EROSION.c",我们可以深入学习如何在 Fluent 中自定义复杂的物理模型,并实现对颗粒侵蚀行为的精确模拟。

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

    ### 构造函数与`return`对象学习 #### 一、引言 本文将深入探讨JavaScript中的构造函数以及如何在构造函数中返回一个对象。在JavaScript编程中,构造函数是一种特殊类型的函数,用于创建和初始化特定类型的新对象。...

    FLUENT UDFs 金属材料属性udf,表面张力、DEFINE-PROTERTY、DEFINE-SPECIFIC-HEAT

    这些源代码可以作为参考,学习如何使用FLUENT的UDF接口来定义复杂的金属材料属性,并进行热力学模拟。 总的来说,理解和编写FLUENT的UDFs是理解和掌握高级流体模拟技术的关键步骤。通过UDFs,我们可以更精确地模拟...

    第四章 DEFINE宏_UDf宏_UDFdescription_

    在CFD(计算流体动力学)领域,Fluent是一款广泛应用的商业软件,用于模拟...通过对"第四章 DEFINE宏_UDf宏_UDFdescription_"的学习,读者将能更好地理解和运用这些工具,从而在解决复杂的流体力学问题时更加得心应手。

    C++/C 宏定义(define)中# ## 的含义

    ### C++/C宏定义(define)...通过本文的学习,我们了解到`#`和`##`在C++/C宏定义中的作用以及如何运用它们来提高代码的灵活性和可读性。希望本文能够帮助读者更好地掌握这些宏定义技巧,并在实际项目中合理利用它们。

    VIVUDF2_CG_MOTION_DEFINE_CG_MOTION_二维运动动网格_

    标题 "VIVUDF2_CG_MOTION_DEFINE_CG_MOTION_二维运动动网格_" 提供的信息表明,这个主题涉及到使用Fluent软件进行流体动力学(CFD)模拟时,利用CG_MOTION功能来定义二维物体的动态运动。描述中的 "fluent DEFINE_CG...

    define的用法和例句.pdf

    在数据分析或机器学习中,`define`可能用于明确指标或特征的计算方式,如“定义‘高收入’为月收入超过5000美元”,这有助于后续分析的标准化。 最后,`define`在讨论抽象概念时也十分有用,如第9个例句中定义“酷...

    NX二次开发UF-DRAW-define-view-boundary1 函数介绍

    NX二次开发UF_DRAW_define_view_boundary1 函数介绍,Ufun提供了一系列丰富的 API 函数,可以帮助用户实现自动化、定制化和扩展 NX 软件的功能。无论您是从事机械设计、制造、模具设计、逆向工程、CAE 分析等领域的...

    #define 宏定义的一些用法总结

    ### #define宏定义的一些用法总结 ...通过对本文介绍的各种宏定义技巧的学习与应用,开发者能够编写出更加高效、易维护的代码。然而,由于宏的特殊性质,在使用时需格外小心,避免因不当使用而导致难以预料的问题。

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

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

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

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

    externC_ifndef_define_endif_pragma onceDemo.zip

    在C++编程中,`extern "C"`、`#ifndef`、`#define` 和 `#endif` 是四种非常重要的预处理器指令,它们在不同场景下有着特定的作用。...通过学习和掌握这些基础,开发者能够更好地编写跨平台、易于维护的软件。

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

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

    eCognition_define教程

    通过以上内容的学习,我们可以了解到eCognition_define教程不仅涵盖了基本的概念介绍,还提供了实用的操作指南和案例分析。掌握了这些知识后,用户能够更加高效地利用eCognition软件进行遥感数据分析,提高研究工作...

    define_tomcat.zip

    【标题】"定义Tomcat"(define_tomcat.zip)是一个学习项目,旨在帮助开发者理解并模仿Apache Tomcat服务器的工作原理。这个压缩包包含了一个小型的案例,它封装了HTTP请求(Request)和响应(Response)对象,通过...

    define_trace.rar_trace

    通过分析和学习`define_trace.c`,开发者可以获得对Linux内核动态跟踪系统更深入的理解,从而更好地进行内核级别的调试和优化工作。对于想要提升内核开发技能或者进行系统级问题排查的人来说,这份代码是宝贵的资源...

    objcircle__define.rar_IDl

    通过这个压缩包,我们可以学习到如何在IDL中使用面向对象编程来创建自定义类,理解类的属性、方法、构造函数、访问修饰符,以及如何实例化对象并调用其方法。这些都是IDL编程中非常重要的基础知识。

    AMX学习,网上那个下载的

    AMX学习是一个涵盖广泛的主题,尤其对于初学者来说,理解其基本概念和操作流程至关重要。AMX是一个先进的控制系统,主要用于智能家居、商业建筑、会议中心等环境的自动化管理。在这个过程中,我们首先需要了解如何...

Global site tag (gtag.js) - Google Analytics