一、宏定义#define

优点:一方面可以节省程序的空间上的篇幅,另外,恰当地使用宏定义可提高程序的时间效率。代码可以写的通俗易懂。可以提高程序的清晰性、可读性,使于修改移植等。

缺点:宏定义的使用实际上也存在副作用,大量的使用会破坏程序的可读性,并给程序的调试带来麻烦,是优点也是缺点。过多的宏定义,代码不容易调试,代码进不去宏定义当前所运行的内容。

一般来说,如果一个函数非常大,一般不宜采用宏定义来进行改造,仅仅是那些小的函数,而且非常影响效率的函数才值得这样去做。

1. 不带参宏定义

例如: #define MAX  1000

 (1)宏名一般用大写

  (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义

  (3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。

  (4)宏定义末尾不加分号;

  (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。

  (6)可以用#undef命令终止宏定义的作用域

  (7)宏定义可以嵌套

  (8)字符串" "中永远不包含宏

2.带参的宏定义

例如:#define ADD(x,y) ((x)+(y))

1)实参如果是表达式容易出问题

  #define S(r) r*r

  area=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b;

  正确的宏定义是#define S(r) (r)*(r)

  (2)宏名和参数的括号间不能有空格

  (3)宏替换只作替换,不做计算,不做表达式求解

  (4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存

  (5)宏的哑实结合不存在类型,也没有类型转换。

  (6)函数只有一个返回值,利用宏则可以设法得到多个值

  (7)宏展开使源程序变长,函数调用不会

  (8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)

)宏定义不分配内存,变量定义分配内存。宏替换发生的过程

二、 宏展开过程

为了理解#define的作用,让我们来了解一下对C语言源程序的处理过程。当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程,见图。 

图1     C语言的编译过程

三、预处理器功能

其中预处理器产生编译器的输出,它实现以下的功能: 

(1)    文件包含 

可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。 

(2)    条件编译 

预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。 

(3)    宏展开 

预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。 

经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。

四、样例贴代码

// 直接替换

#define  max   1000

// ##和# 的使用,##链接,#把字符变为字符串

#define  test(classname,len,type)\

char*  unit_test_binary_to_geometry_service_pid = "pj."#classname#len#type"id";\

#define  str(x)   #x

// 返回一个字符

#define getch(c) #@c

// 定义一个某类型的变量名称。

#define cat(x,y) x##y

void  main()

{

string str_ =  str(waht);

char* tmp_cat = "this is a test";

string cat(var,1235);

var1235 = tmp_cat;

char ch_ = ch(t);

test(A,12,int)

string temp = unit_test_pid;

}

自己的用例:

#define  unit_test_marco_derived_start(test_class_name,test_class_service_name,test_class_service_pid)\

test_class_service_name *          ___##test_class_service_name;\

void test_unit_module (unit_test_writer::ptr test_writer_);\

static char*  unit_test_##test_class_service_pid = "rw.unit.test."#test_class_name;\

\

class  unit_test_##test_class_name\

:public  unit_test\

{\

public:\

typedef rw_shared_ptr< unit_test_##test_class_name > ptr;\

typedef rw_shared_ptr<const unit_test_##test_class_name > const_ptr;\

\

unit_test_##test_class_name (unit_test_service* test_service_,runtime* runtime_)\

: _unit_test_service( test_service_ )\

, _runtime( runtime_ )\

{\

___##test_class_service_name = ( test_class_service_name * ) _runtime->get_service( test_class_service_pid )->get_service();\

}\

virtual ~ unit_test_##test_class_name (){}\

\

virtual void test(unit_test_result::ptr test_result_, unit_test_writer::ptr test_writer_)\

{\

test_writer_->write("\n -----------------start to test "#test_class_name"...---------------------\n");\

test_unit_module (test_writer_);\

test_writer_->write("\n -----------------end to test "#test_class_name"...---------------------\n");\

return;\

}\

private:\

unit_test_service*                 _unit_test_service;\

runtime*                           _runtime;\

private:\

};

当然宏定义的用法不止这么点,多种多样。

五、预处理命令

对于预处理命令,还有很多。也把别人的贴出来供各位参考:

  宏定义不分配内存,变量定义分配内存。宏替换发生的过程 

预处理命令由#(hash字符)开头, 它独占一行, #之前只能是空白符. 以#开头的语句就是预处理命令, 不以#开头的语句为C中的代码行. 常用的预处理命令如下:



#define              定义一个预处理宏

#undef               取消宏的定义



#include            包含文件命令

#include_next   与#include相似, 但它有着特殊的用途



#if                      编译预处理中的条件命令, 相当于C语法中的if语句

#ifdef                判断某个宏是否被定义, 若已定义, 执行随后的语句

#ifndef             与#ifdef相反, 判断某个宏是否未被定义

#elif                  若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if

#else                与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else

#endif              #if, #ifdef, #ifndef这些条件命令的结束标志.

defined            与#if, #elif配合使用, 判断某个宏是否被定义



#line                标志该语句所在的行号

#                      将宏参数替代为以参数值为内容的字符窜常量

##                   将两个相邻的标记(token)连接为一个单独的标记

#pragma        说明编译器信息



#warning       显示编译警告信息

#error            显示编译错误信息

说明:近期用了一些宏定义,所以就抽空整理了网上的部分东西。

若有问题,请随时联系!

宏定义#define整理的更多相关文章

  1. 宏定义#define和typedef的区别和典型范例题目辨析

    宏定义#define pStr char*  ,是直接把程序中出现pStr的地方替换成char* ,直接替换: typedef  char * pStr; 是给char*定义一个别名叫做 pStr; ...

  2. C语言宏定义#define用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...

  3. 【C++】内联函数(inline)和宏定义(# define)的优劣及其区别

    一.宏定义:# define 1.为什么要使用宏? 因为调用宏比调用函数更有效率,函数的调用必须要将程序的执行顺序转移到函数所存放的内存地址中,将函数程序内容执行完后,再返回到执行该函数前的地方,这种 ...

  4. c语言宏定义#define的理解与资料整理

    1. 利用define来定义 数值宏常量 #define 宏定义是个演技非常高超的替身演员,但也会经常耍大牌的,所以我们用它要慎之又慎.它可以出现在代码的任何地方,从本行宏定义开始,以后的代码就就都认 ...

  5. [转]c语言宏定义#define的理解与资料整理

    原文地址:http://www.cnblogs.com/haore147/p/3646934.html 1. 利用define来定义 数值宏常量 #define 宏定义是个演技非常高超的替身演员,但也 ...

  6. C语言 预处理二(宏定义--#define)

    //#define 宏定义(宏定义一般大写) //知识点一-->#define的作用域:从#define开始,从上往下,如果遇到#undef就到#undef处结束,如果没有就是作用于当前整个文件 ...

  7. iOS之宏定义#define

    最基本的宏定义用法 #define aaa bbb 表示用aaa替换bbb的内容. 宏作用范围 宏的作用范围是在当前文件内, 如果需要作用于其他类(如在类b调用类a已定义宏),那么需要在类b引入类a的 ...

  8. 读书笔记 effective c++ Item 2 尽量使用const,枚举(enums),内联(inlines),不要使用宏定义(define)

    这个条目叫做,尽量使用编译器而不要使用预处理器更好.#define并没有当作语言本身的一部分. 例如下面的例子: #define ASPECT_RATIO 1.653 符号名称永远不会被编译器看到.它 ...

  9. C++ 宏定义#define 中##的使用

    在C++的宏定义中,符号##一般是用于连接,包括参数的连接,参数与标识符的连接等,然后形成一个新的标识符. 下面举几个例子来进行说明. eg1: #define ADD(a,b) a##b #defi ...

随机推荐

  1. JavaScript数组的某些操作(二)

    7.颠倒数组中元素的顺序(注意:不是为数组排序)--reverse方法 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitiona ...

  2. Python print 语句(Python 2 与 Python 3)

    1. python 3.x 中的 print print 在 Python 3.x 的环境里是内置函数(built-in function): python 3 的 print 语句支持(python ...

  3. 移动端meta几个值的设置以及含义

    <!-- 为移动设备添加 viewport --> <meta name="viewport" content="width=device-width, ...

  4. Yahoo!团队:网站性能优化的35条黄金守则(转)

    Excetional Performance 团队总结出了一系列可以提高网站速度的方法.可以分为 7大类 35条.包括内容 .服务器 . CSS . JavaScript .Cookie .图片 .移 ...

  5. 73,QT指针数组实战(指针数组与数组指针)

    //指针数组,每一个指针都是一个MainWindow // MainWindow *w[3][4]; // for(int i=0;i<3;i++) // { // for(int j=0;j& ...

  6. MATLAB 最优化计算 (一)

    1,令多行命 —— 逗号 VS 分号 2,管理工作空间 —— who , whos , clear , save , load , length (向量显示其长度,矩阵显示行数与列数中的较大数)  s ...

  7. Dubbo简易学习

    0.  Dubbo简易介绍 DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000, ...

  8. 微信小程序从零开始开发步骤(八)引入框架WeUI

    首先来看下WeUI的官方介绍: WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一.在微信小程序的开发过程中,涉及到的前端 ...

  9. C#引用c++DLL结构体数组注意事项(数据发送与接收时)

    本文转载自:http://blog.csdn.net/lhs198541/article/details/7593045 最近做的项目,需要在C# 中调用C++ 写的DLL,因为C# 默认的编码方式是 ...

  10. 用了Redis里面的map和set

    map的操作用 hset,hget等 set的操作有 sadd sismember等 参考下面: http://blog.csdn.net/kwsy2008/article/details/48467 ...