宏定义与宏替换

上网导航 2023-12-04 150 0条评论
摘要: 文章浏览阅读1.4w次,点赞4次,收藏24次。一. c /c++语言中使用宏的主要目的主要有 3 个:1. 提高代码的可读性;把用到的常量定义成有意义的名字;2. 无需函数调用...

一. 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
#define n  2+2
int main()
{
  int a = 0;
  a = n * n;
  return 0;
}

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

#include
#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*/

文章版权及转载声明:

作者:上网导航本文地址:https://www.90xe.com/post/6673.html发布于 2023-12-04
文章转载或复制请以超链接形式并注明出处技术导航

分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏