c++中define用法

define在c++语言中用法比较多,这里对其进行整理。

1.无参宏定义

无参宏的宏名后不带参数。
其定义的一般形式为:

#define  标识符  字符串

其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。
例如:

#define MAXNUM 99999

这样MAXNUM就被简单的定义为99999。

2.有参宏定义

C++语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。
对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参宏定义的一般形式为:

 #define  宏名(形参表)  字符串

在字符串中含有各个形参。在使用时调用带参宏调用的一般形式为:宏名(实参表);
例如:

#define add(x, y) (x + y)
int main()
{cout << "1 plus 1 is " << add(1, 1.5) << ".\n";//输出“1 plus 1 is 2.5.”system("pause");return(0);
}

这个“函数”定义了加法,但是该“函数”没有类型检查,有点类似模板,但没有模板安全,可以看做一个简单的模板。

注意:该“函数”定义为(a + b),在这里加括号的原因是,宏定义只是在预处理阶段做了简单的替换,如果单纯的替换为a + b时,当你使用5 * add(2, 3)时,被替换为5 * 2 + 3,值为13,而非5 * (2 + 3),值为25。

3.宏定义中的特殊操作符
define 中的特殊操作符有#,##和… and __VA_ARGS__
(1)#
假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串。例如,如果x是一个宏参量,那么#x可以把参数名转化成相应的字符串。该过程称为字符串化。

例如:

#incldue <stdio.h>
#define PSQR(x) printf("the square of" #x "is %d.\n",(x)*(x))
int main(void)
{int y =4;PSQR(y);//输出:the square of y is 16.PSQR(2+4);//输出:the square of 2+4 is 36.return 0;
}

(2)##

##运算符可以用于类函数宏的替换部分。另外,##还可以用于类对象宏的替换部分。这个运算符把两个语言符号组合成单个语言符号。
例如:

#include <stdio.h>
#define XNAME(n) x##n
#define PXN(n) printf("x"#n" = %d\n",x##n)
int main(void)
{int XNAME(1)=12;//int x1=12;PXN(1);//printf("x1 = %d\n", x1);//输出:x1=12return 0;
}

(3)可变参数宏 …和__VA_ARGS__

__VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。
实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏__VA_ARGS__就可以被用在替换部分中,替换省略号所代表的字符串。

例如:

#define PR(...) printf(__VA_ARGS__)
int main()
{int wt=1,sp=2;PR("hello\n");//输出:helloPR("weight = %d, shipping = %d",wt,sp);//输出:weight = 1, shipping = 2return 0;
}

省略号只能代替最后面的宏参数。
#define W(x,…,y)错误!
但是支持#define W(x, …),此时传入的参数个数必须能够匹配。

这里再介绍几个系统的宏:

1) __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的”,”去掉的作用,否则会编译出错, 你可以试试。
2) __FILE__ 宏在预编译时会替换成当前的源文件名
3) __LINE__宏在预编译时会替换成当前的行号
4) __FUNCTION__宏在预编译时会替换成当前的函数名称

4.宏定义中的多行定义

非常经典。

#define MACRO(arg1, arg2) do { /
/* declarations */ /
stmt1; /
stmt2; /
/* ... */ /
} while(0) /* (no trailing ; ) */

记得要在每一个换行的时候加上一个”/”

5.宏定义中的条件编译

在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。

#ifdef WINDOWS
......
(#else)
......
#endif
#ifdef LINUX
......
(#else)
......
#endif

可以在编译的时候通过#define设置编译环境。

6.如何取消宏

//定义宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]

7.防止重复包含头文件
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。
通过条件编译开关来避免重复包含(重复定义)
例如:

#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件内容
…
#endif

小结及说明

1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
2) 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
3) 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。只要函数定义在#undefine之后,则函数无法使用#define的内容。
4) 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。
5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。
例如:

 #define PI 3.1415926#define S PI*y*y          /* PI是已定义的宏名*/

6) 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。
7) 可用宏定义表示数据类型,使书写方便。
应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。
宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。
请看下面的例子:

#define PIN1 int *
typedef (int *) PIN2;

从形式上看这两者相似, 但在实际使用中却不相同。
下面用PIN1,PIN2说明变量时就可以看出它们的区别:
PIN1 a,b;在宏代换后变成:
int *a,b;
表示a是指向整型的指针变量,而b是整型变量。
然而:
PIN2 a,b;
表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。
8) 对“输出格式”作宏定义,可以减少书写麻烦。
例如:

#define P printf
#define D "%d\n"
#define F "%f\n"
main(){int a=5, c=8, e=11;float b=3.8, d=9.7, f=21.08;P(D F,a,b);P(D F,c,d);P(D F,e,f);
}

9)带参宏定义中,宏名和形参表之间不能有空格出现。
10)在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。
11)在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

c/c++中define用法详解及代码示例相关推荐

  1. pdo mysql limit_PHP mysql中limit用法详解(代码示例)

    在MySQL中,LIMIT子句与SELECT语句一起使用,以限制结果集中的行数.LIMIT子句接受一个或两个offset和count的参数.这两个参数的值都可以是零或正整数. offset:用于指定要 ...

  2. mysql中函数mid_MySQL MID()函数的用法详解(代码示例)

    在MySQL中,MID()函数返回从指定位置开始的子字符串. MID()和SUBSTR()都是SUBSTRING()的同义词. 基本语法是这样的:MID(str,pos,len) 这里,str是字符串 ...

  3. mid函数怎么用mysql_MySQL MID()函数的用法详解(代码示例)-mysql教程-学派吧

    在MySQL中,MID()函数返回从指定位置开始的子字符串. MID()和SUBSTR()都是SUBSTRING()的同义词. 基本语法是这样的: MID(str,pos,len) 这里,str是字符 ...

  4. php 配置 error_reporting,PHP中error_reporting()用法详解 技术分享

    在php中error_reporting函数有什么作用? error_reporting([ int $level ] ) - 设置应该报告何种 PHP 错误. 该函数能够在运行时设置 error_r ...

  5. mysql increment_mysql中auto_increment用法详解

    在mysql中AUTO_INCREMENT类型的属性用于为一个表中记录自动生成ID功能,也就是会自动自增一个ID了,如现在是1下次会自动是2了,就这么简单,下面来看mysql中auto_increme ...

  6. 【 Python 中 int 用法详解】(转载)

    Python 中 int 用法详解 欢迎转载,转载请注明出处! 文章目录 Python 中 int 用法详解 0. 参考资料 1. int 的无参数调用 2. int 接收数字作为参数 3. int ...

  7. Python 中 int 用法详解

    Python 中 int 用法详解 欢迎转载,转载请注明出处! 文章目录 Python 中 int 用法详解 0. 参考资料 1. int 的无参数调用 2. int 接收数字作为参数 3. int ...

  8. Python中self用法详解

    Python中self用法详解 https://blog.csdn.net/CLHugh/article/details/75000104 首页 博客 学院 下载 图文课 论坛 APP 问答 商城 V ...

  9. c 语言中set的用法,C++中set用法详解

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构 ...

  10. sql语句中exists用法详解

    文章目录 一.语法说明 exists: not exists: 二.常用示例说明 1.查询a表在b表中存在数据 2.查询a表在b表中不存在数据 3.查询时间最新记录 4.exists替代distinc ...

最新文章

  1. 容器 root权限运行_【漏洞通告】Containerd容器逃逸漏洞通告 (CVE202015257)
  2. qtablewidget限制输入类型_对敏感型电子信号输入实施过压保护的可靠新方法
  3. Uboot配置界面详解
  4. php根据地址获取经纬度
  5. python 第一行 报错_初学Python-只需4步,爬取网站图片
  6. SwarmKit知多少——来自源码世界的深入解读
  7. mysql限制用户只能访问指定数据库
  8. python中for和while区别_Python的while 1跟while True到底有什么区别?
  9. QQ防撤回9.0.2 软件 源码 源文件
  10. Mac IDEA 顶部的菜单栏不见了
  11. pg_squeeze安装及简单使用
  12. 多台路由器连接,实现全网可达
  13. 【打卡-Coggle竞赛学习2023年2月】图节点嵌入
  14. git 加速代理设置,单仓库设置代理,指定仓库设置单独代理
  15. 2017下半年掘金日报优质文章合集:Android篇,android开发工程师
  16. ORACLE分区表梳理系列(二)- 分区表日常维护及注意事项(红字需要留意)
  17. Chrome浏览器上传和下载就会崩溃的解决方法
  18. 了解MySQL,走进他的心
  19. android tabhost黑色背景,怎么设置tabhost的背景颜色
  20. UIImagePickerController 选照片 拍照 录视频

热门文章

  1. 持续提高安卓应用安全性与性能
  2. php打印文本中随机行内容
  3. nginx cache配置
  4. Centos 6.5之LAMP学习笔记
  5. valgrind- 内存泄漏-how to install and use
  6. 32.分配数组的方式
  7. 小白错误三——Collider存在,刚体存在情况下,不能触发OnCollisionEnter函数
  8. java 定义mysql树形菜单
  9. 命令行参数解析函数 getopt
  10. scala学习笔记(四)样本类与模式匹配