C++ "#"的作用和使用方法
本系列文章由 @yhl_leo 出品,转载请注明出处。
文章链接: http://blog.csdn.net/yhl_leo/article/details/48879093
1 #
和##
的作用和使用方法
C/C++ 的宏中,#
的功能是将其后面的宏參数进行字符串化操作。简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引號。##
连接符号由两个井号组成,其功能是在带參数的宏定义中将两个子串联接起来,从而形成一个新的子串。
但它不能够是第一个或者最后一个子串。
#include <iostream>
using namespace std;
#define WARN_IF(EXP) if(EXP) cerr << #EXP << endl;
#define paster( n ) cout << "token" << #n << " = " << n << endl;
#define _CONS(a, b) int(a##+##b)
#define _STRI(s) #s
void main()
{
int div = 0;
WARN_IF(div == 0); // prints : div == 0
paster(9); // prints : token9 = 9
cout << _CONS(1, 2) << endl; // prints : 3
cout << _STRI(INT_MAX) << endl; // prints : INT_MAX
}
凡是宏定义里实用#
或##
的地方宏參数是不会再展开,比如_STRI(INT_MAX)
中的INT_MAX
就不会被展开为2147483647。
假设想要使当中的宏參数展开,则须要多加一层中间转换宏:
#define STRI(s) _STRI(s)
cout << STRI(INT_MAX) << endl; // prints : 2147483647
加这层宏的用意是把全部宏的參数在这层里全部展开。那么在转换宏里的宏就能得到对应的宏參数。
接下来,我们来了解通过预处理指令创建条件编译參数控制代码编译的一些使用方法。
2 #include
的使用方法
包括头文件的操作,通常有两种格式:
#include <header-file>
#include "header-file"
<>
和""
表示编译器在搜索头文件时的顺序不同:
<>
表示从系统文件夹下開始搜索,然后再搜索PATH环境变量所列出的文件夹,不搜索当前文件夹""
是表示从当前文件夹開始搜索,然后是系统文件夹和PATH环境变量所列出的文件夹。
所以,系统头文件一般用<>
,用户自定义的则能够使用""
,加快搜索速度。
除此外,写代码多了就会发现,有些头文件之间的相互包括是有隐藏依赖关系的。一定要加以注意。Google C++ Style Guide中也强调使用标准的头文件包括顺序可增强可读性, 避免隐藏依赖:
1 相关文件(优先位置,如
dir2/foo2.h
)
2 C系统文件
3 C++ 系统文件
4 其它库的.h
文件
5 本项目内.h
文件
3 #if
,#elif
,#else
,#endif
使用方法
// structure 1
#if constant_expression
#else
#endif
// structure 2
#if constant_expression
#elif constant_expression
#endif
这里的结构跟常见的if...else
和if...else if...else
语句相似,当#if
后的条件为非零(true)时,编译#if
和#else
或#elif
之间的代码。否则编译#else
和#endif
之间的代码(或者推断#elif
后的条件是否非零(true),决定是否编译#elif
和#endif
之间的代码)。
#if 1
cout << "Hello world!" << endl;
#else
cout << "Nice to meet you!" << endl;
#endif
// prints : Hello world!
#if 1
cout << "Hello world!" << endl;
#elif 1
cout << "Nice to meet you!" << endl;
#endif
// prints: Hello world!
// Nice to meet you!
4 #define
,#undef
,#ifdef
,#ifndef
使用方法
#define
是大家都常见的宏定义方法。使用方法结构为:
// #define identifier replacement-code
#define PI 3.1415926
#define ADD(x,y) (x + y)
#undef
顾名思义。就是从该处取消前面已经定义的宏,假设标识符当前没有被定义称为一个宏名称,就会忽略该指令:
// #undef identifier
#undef PI
#ifdef
和#ifndef
含义相反,前者含义为假设定义了该宏。则编译对应代码;后者则为假设未定义该宏。则编译对应代码。通用结构为:
/*
* #ifdef identifier
* #else or #elif
* #endif
**/
#define DEBUG
#ifdef DEBUG
cout << "This is a debug message." << endl;
#endif
// prints : This is a debug message.
/*
* #ifndef identifier
* #else or #elif
* #endif
**/
#ifndef DEBUG
cout << "This is a debug message." << endl;
#endif
// prints nothing
在编程时,为了避免头文件重定义,常常使用的就是#define
配合条件编译解决:
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
// ...
class MyHeaderFile
{
// ....
};
#endif // MY_HEADER_FILE_H
除此以外,还有#pragma once
的使用方法,仅仅要在头文件的最開始增加这条指令就能够保证头文件被编译一次。
(在全部的预处理指令中,#pragma
指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完毕一些特定的动作,本文不多讲述。)
5 #line
使用方法
#line
命令是用于更改__LINE__
和 __FILE__
变量的值。
__FILE__
和__LINE__
描写叙述被读取的当前文件和所在行数。
// #line line-number filename
int main()
{
#line 10 "main.cpp"
cout << __FILE__ << " " << __LINE__ << endl;
}
// prints : main.cpp 10
6 #error
使用方法
#error
会直接导致程序停止编译并输出指定的错误信息:
// #error message
#ifndef VERSION
#error Version number not specified.
#endif
// The compiler will halt compiling and return with the specified error message:
// fatal error C1189: #error : Version number not specified.
C++ "#"的作用和使用方法的更多相关文章
- JAVA 注解的几大作用及使用方法详解
JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...
- serialVersionUID的作用以及设置方法(转)
声明:本篇文章是转载的 http://blog.csdn.net/kakaxi_77/article/details/8129070 http://snowlotus.iteye.com/blog/2 ...
- 在Android开发中替换资源图片不起作用的解决方法
现象 在android开发中,经常会需要替换res\drawable中的图片,打开res\layout下的文件预览布局页面发现图片已经被替换,但在模拟器或者真实机器上运行时发现该图片并没有被替换,还是 ...
- 【转】 PreTranslateMessage作用和使用方法
PreTranslateMessage作用和使用方法 PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用, ...
- Linux中PATH环境变量的作用和使用方法
关于PATH的作用:PATH说简单点就是一个字符串变量,当输入命令的时候LINUX会去查找PATH里面记录的路径.比如在根目录/下可以输入命令ls,在/usr目录下也可以输入ls,但其实ls这个命令根 ...
- PHP trim()函数的作用和使用方法
PHP trim()函数一般是用来去除字符串首尾处的空白字符(或者其他字符),一般在用在服务端对接收的用户数据进行处理,以免把用户误输入的空格存储到数据库,下次对比数据时候出错. 该函数有两个参数,第 ...
- PreTranslateMessage作用和使用方法
PreTranslateMessage作用和使用方法 PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用, ...
- header中Content-Disposition的作用与使用方法
下载文件的时候会使用: Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件.Content-disposition其实可以控制用 ...
- 类属性与对象实现,init方法的作用,绑定方法,绑定方法与普通函数的区别,继承,抽象与继承,派生与覆盖
今日内容: 1.类属性与对象属性 2.init方法的作用 3.绑定方法 4.绑定方法与普通函数的区别(非绑定方法) 5.继承 6.抽象与继承 7.派生与覆盖 1.类属性与对象属性 类中应该进存储所有对 ...
随机推荐
- 【bzoj4184】shallot 线段树+高斯消元动态维护线性基
题目描述 小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏. 每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且 让小葱从自己手中的小 ...
- NYOJ——301递推求值(矩阵快速幂)
递推求值 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的 ...
- bzoj 1003 [ZJOI2006]物流运输(最短路+dp)
[ZJOI2006]物流运输 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8973 Solved: 3839[Submit][Status][Di ...
- Lua local function与function区别
1 使用function声明的函数为全局函数,在被引用时可以不会因为声明的顺序而找不到 2 使用local function声明的函数为局部函数,在引用的时候必须要在声明的函数后面 例子: 下面这段代 ...
- d3 svg简单学习
矩形 <rect x="/> 圆形 <circle cx="/> 椭圆 <ellipse cx="/> 线 <line x1=& ...
- 2016 Multi-University Training Contest 10 solutions BY BUPT
1001. 一个数组上的两个区间求中位数,可以通过分类讨论直接找到中位数,复杂度O(1).不过本题数据较小,优美的log(n)也可过. 1002. 直接求得阴影面积表达式即可. 1003. 二分完成时 ...
- 【HDU3507】Print Article(斜率优化DP)
单调队列DP复出练手题 朴素方程dp[i]=min(dp[j]+(s[i]-s[j-1])^2+m 你懂得 ..]of int64; a,q:array[..]of longint; n,m,i,t, ...
- c#.NET的事件与委托例子
原文发布时间为:2008-07-25 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- C#知识点总结:Monitor和Lock以及区别
Monitor对象 1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取 ...
- 如何让一个现有的程序集运行在Silverlight环境中
故事是这样的:我们有一个组件,是一个标准的Class Library,里面有一些代码是实现了某些计算或者业务逻辑.例如下面这样 然后,我们做了一个Silverlight的应用程序,和一个用于运行该程序 ...