宏定义与宏替换

一. c /c++语言中使用宏的主要目的主要有 3 个:
1. 提高代码的可读性;
把用到的常量定义成有意义的名字;
2. 无需函数调用,运行效率高;
对于一些简单的操作,无需调用函数,虽然编程是强调模块化,但是函数调用时,需要保护现场和恢复现场。这些都需要耗时。对于复杂的操作来讲,这些耗时可以不计,但是对于简单的操作,则效率低下。利用宏来代替简单的操作,则可以提高程序的运行效率。
3. 可维护行好;
对于用得比较多的常量或者简单操作,一旦需要修改,则只需要修改宏定义处,不需要逐条修改。

二. 宏定义命令 : #define
1 . #define命令主要是将一个标识符替换为一个字符串,该标识符称为宏名,被替换的字符串被称为替换文本
2. 用法:
主要有两种格式,一个是简单的宏定义,另一个是带参数的宏定义;
简单的宏定义: #define <宏名> <替换文本>
例: #define pi 3.1415
带参数的宏定义:#define <宏名> (<参数列表>) <宏体>
例: #define A(x) x

三. 宏替换
当宏定义好后,在程序中使用宏名就称为宏替换。当程序进行编译时实际上经过了预处理,编译(生成中间代码,即从源程序翻译为中间语言,即汇编),汇编(将汇编语言翻译成机器代码,即二进制代码),链接(将目标文件生成 .exe文件)。宏替换就发生在预处理(也叫预编译)阶段,也就是说在编译之前(生成二进制文件之前)就已经完成了文本的替换工作。
关于预处理主要完成的工作是:
1.文件包含,将#include包含的文件找到,并在#include处进行展开;
2.条件编译,根据#if #ifdef 等编译命令及其后的条件,将源程序的一部分包含进来或排除在外,通常把排除在外的语句换成空行。
3.宏展开,将程序中所用到的宏展开成宏定义的替换文本。经过宏展开之后的程序与之前的源程序的只是简单的文本替换,并无计算功能。这是理解宏的要点。
四. 使用宏要注意的问题
1.使用简单宏出现的问题

#include<stdio.h>
#define n  2+2
int main()
{
  int a = 0;
  a = n * n;
  return 0;
}

2.使用带参数的宏出现的问题

#include<stdio.h>
#define product(a) a*a
int main()
{
  int i = 4;
  int j = product(i++);
  printf("i = %d\n",i);
  printf("j = %d\n",j);
  j = product(++i);
  printf("i = %d\n",i);
  printf("j = %d\n",j);
  return 0;
}

在vs带的编译器下,程序输出结果 i = 6 j =16 i = 8 j = 64

四. 结语
本文主要讲了宏定义的用法以及要使用时要注意的东西,同时注意到宏替换在预处理阶段完成,只是进行文本替换。

五. 常用的宏定义

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

#ifndef BODYDEF_H 
#define BODYDEF_H 
 //头文件内容 
#endif

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

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

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

#define OFFSETOF( type, field ) ( (size_t) &(( type *) 0)-> field )

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

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

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

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

6 将一个字母转换为大写

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

7 判断字符是不是10进值的数字

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

8 判断字符是不是16进值的数字

#define HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a'' && (c) <= ''f'') )

9 防止溢出的一个方法

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

10 返回数组元素的个数

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

11 使用一些宏跟踪调试
ANSI标准说明了五个预定义的宏名。它们是

_LINE_ /*(两个下划线),对应%d*/
_FILE_ /*对应%s*/
_DATE_ /*对应%s*/
_TIME_ /*对应%s*/

摘自:http://blog.chinaunix.net/uid-21372424-id-119797.html

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值