zoukankan      html  css  js  c++  java
  • 宏定义与宏替换

    一. 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;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    #include<stdio.h>
    #define product(a) a*a
    int main()
    {
      int i = 4;
      int j = product(i++);
      printf("i = %d
    ",i);
      printf("j = %d
    ",j);
      j = product(++i);
      printf("i = %d
    ",i);
      printf("j = %d
    ",j);
      return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

    五. 常用的宏定义

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

    #ifndef BODYDEF_H 
    #define BODYDEF_H 
     //头文件内容 
    #endif
    • 1
    • 2
    • 3
    • 4

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

    #define MEM_B( x ) ( *( (byte *) (x) ) ) 
    #define MEM_W( x ) ( *( (word *) (x) ) )
    • 1
    • 2

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

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

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

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

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

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

    6 将一个字母转换为大写

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

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

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

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

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

    9 防止溢出的一个方法

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

    10 返回数组元素的个数

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

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

    _LINE_ /*(两个下划线),对应%d*/
    _FILE_ /*对应%s*/
    _DATE_ /*对应%s*/
    _TIME_ /*对应%s*/
    • 1
    • 2
    • 3
    • 4

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

    Higher you climb, more view you will see.
  • 相关阅读:
    windows程序中的数据绑定
    dbhelper
    数据库错题
    构建布局良好的windows程序
    初始windows程序
    asp.net 文件下载 解决文件名乱码
    asp.net 文件下载 文件名称乱码 处理~~
    ASP.NET上传文件并记录到数据库
    Jquery配合Asp.Net无刷新删除指定服务器上的文件!
    Frame、Iframe、Frameset 的区别
  • 原文地址:https://www.cnblogs.com/yyfighting/p/12500635.html
Copyright © 2011-2022 走看看