宏替换是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.内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。
下例:
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
发表评论
-
set容器的反向迭代器
2013-05-02 16:56 3673#include <iostream> #in ... -
对于CRITICAL_SECTION用法的介绍和理解[转]
2013-04-08 11:50 2088很多人对CRITICAL_SECTION ... -
二维数组知识
2012-09-15 17:20 767二维数组和指针⑴ 用 ... -
Realloc的使用
2012-08-14 11:04 780realloc 用过很多次了。 ... -
extern C的由来
2012-08-09 10:14 661时常在cpp的代码之中看到这样的代码: #ifdef ... -
C++类对象的创建过程
2012-07-26 16:02 890分配空间(Allocation) ... -
静态数据成员和静态成员函数
2012-07-26 15:04 3050静态类成员包括静态数据成员和静态函数成员两部分。 与 ... -
复制构造函数(拷贝构造函数)以及深浅拷贝
2012-07-25 22:39 1385对于普通对象而言复制是很简单的,一般是将变量或者常量赋值给某 ... -
cin、cin.get、cin.getline()、getline()、gets()的用法【转】
2012-07-24 20:05 777学C++的时候,这几个输入函数弄的有点迷糊;这里做个小结,为了 ... -
编程笔记(07-24)
2012-07-24 15:15 6221 #include < stdio.h ... -
堆、栈解疑
2012-07-12 21:53 533一、预备知识—程序的内存分配 一个由C/C++编译的程序 ... -
指针和内存分配的深度理解
2012-07-12 18:57 979一 :关于指针和堆的内存分配 先来介绍一下指针: 指针一种 ... -
数组指针和指针数组
2012-07-12 18:56 1130先看一下基本的形式,我们从这里起步! ----------- ... -
const指针和指向const的指针
2012-07-12 10:30 2068指向const对象的指针 ... -
typedef的学习
2012-07-11 15:03 664typedef,顾名思义,为“类型定义”,可以解释为:将一种数 ... -
函数指针和指针函数
2012-07-11 11:21 531【函数指针】 ... -
sizeof 深研
2012-07-11 09:39 6331、什么是sizeof 首先看一下sizeof ... -
内存对齐问题
2012-07-10 22:35 10411.内存数据对齐的原因: 无论如何,为了提高程序的性 ... -
指针深究
2012-07-09 21:55 538在说指向指针的指针之前,不得不说指向变量的指针。先看如下示例: ... -
C语言文件使用方式详解
2012-07-04 10:23 708文件的打开(fopen函数) f ...
相关推荐
不是很清楚把构造函数和类联系起来反正我学的烂大家 看哈 我传的 是盗版
本文主要介绍了C语言中const与#define的区别,希望对你的学习有所帮助。
经过各种尝试,居然成了,特此记录分享一下,方便大家学习。 char A_param=0; char B_pramm=0; //添加宏定义 #define OBJECT A #define DEFINE_(X) X##_param //一次定义 #define DEFINE(X) DEFINE_(X) //再次定义 ...
【Huan】_傲視群雄的全塔式機殼!_支援18顆硬碟、420水冷!!_Fractal_Design_Define_7_XL深度評
主要给大家介绍了关于require.js中define函数的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用require.js中的define函数具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
学习了这么多年C语言,说实话对宏自以为了如指掌了,没想到看内核代码的时候还是那么吃力,设备驱动代码中有很多这样或者那样的宏定义,各种define,博主在学习的过程中将C语言中所出现的#define定义整理总结了一下...
C++中不但可以用define定义常量还可以用const定义常量,下面这篇文章主要给大家分析介绍了关于C++中const与#define的利弊,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...
学习了这么多年C语言,说实话对宏自以为了如指掌了,没想到看内核代码的时候还是那么吃力,设备驱动代码中有很多这样或者那样的宏定义,各种define,在学习的过程中将C语言中所出现的#define定义整理总结了一下,供...
本文主要给大家介绍的是关于Require.JS中define定义方式的相关内容,分享出来供大家参考学习,下面来看看详细的介绍: 定义简单的键值对 define({ color: "black", size: "unisize" }); 定义不带依赖的函数 ...
学习eCognition的资料 DataIO API 用户指导手册
#define XX00 (GPIOA->IDR &GPIO;_Pin_0)//PA0 #define XX01 (GPIOA->IDR &GPIO;_Pin_1)//PA1 #define XX02 (GPIOC->IDR &GPIO;_Pin_5)//PC5 #define XX03 (GPIOC->IDR &GPIO;_Pin_6)//PC6 #define XX04 (GPIOC->IDR...
自己学习总结的discuz x2笔记,相信对你有帮助!
#define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately*/ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error ...
- 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_...
入门级学习笔记,试验用的脚本. 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....
如果你不想花时间学习require.js,也不想翻看长篇的cmd/amd规范,那么这个mini-define就是你不错的选择。如果你之前用过sea.js或require.js那么mini-define更加高效,更加轻量,更加易用。项目地址:github 用法 首先...