本系列文章由 @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...elseif...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++ "#"的作用和用法的更多相关文章

  1. serialVersionUID, ObjectInputStream与ObjectOutputStream类,Serializable接口,serialVersionUID的作用和用法

    ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入 Ser ...

  2. Oracle函数over(),rank()over()作用及用法--分区(分组)求和& 不连续/连续排名

    (1)   函数:  over()的作用及用法:    -- 分区(分组)求和. RANK ( ) OVER ( [query_partition_clause] order_by_clause )D ...

  3. Linq中关键字的作用及用法

    Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...

  4. JSP九大内置对象的作用和用法总结?

    JSP九大内置对象的作用和用法总结? 1.request对象javax.servlet.http.HttpServletRequest request对象代表了客户端的请求信息,主要用于接受通过HTT ...

  5. (转载)MySQL数据类型中DECIMAL的作用和用法

    (转载)http://database.51cto.com/art/201005/201651.htm 在MySQL数据类型中,例如INT,FLOAT,DOUBLE,CHAR,DECIMAL等,它们都 ...

  6. PreTranslateMessage作用和用法

    PreTranslateMessage作用和用法  PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗体的消息都要通过这里,比較经常使用, ...

  7. ViewHolder的作用和用法

    一直都看别人用ViewHolder,自己也用过,却不知道它的作用是什么?但知道肯定很有用,而且现在android studio应该有直接生产Viewholder的插件, 不过博主我是个新手,就没尝试去 ...

  8. Oracle分析函数及常用函数: over(),rank()over()作用及用法--分区(分组)求和& 不连续/连续排名

    (1)   函数:  over()的作用及用法:    -- 分区(分组)求和. sum() over( partition by column1 order by column2 )主要用来对某个字 ...

  9. og标签对SEO的作用及用法

    meta property=og标签对SEO的作用及用法,如果你仔细观察会发现本站点<head>代码中有一段:"property="og:image"这段代码 ...

  10. PHP strip_tags() 函数的作用和用法

    strip_tags()函数可以轻松实现从字符串中去除 HTML 和 PHP 标记. 使用方法: trip_tags ( string $str [, string $allowable_tags ] ...

随机推荐

  1. win7_64

    转到YLMF DOS工具,输入ghost然后回车 enter后 选择options进入

  2. 具体解释linux文件处理的的经常使用命令

    原创Blog.转载请注明出处 附上之前訪问量比較高的几篇linux博客 本人使用shell的8个小技巧 grep的九个经典使用场景 sed命令具体解释 awk命令具体解释 linux中全部的东西都是文 ...

  3. SQL SERVER读书笔记:阻塞与死锁

    阻塞是事务隔离带来的副作用,而并不是SQL SERVER的错. 死锁则是互相争用资源而引发.由于死锁会选择牺牲者,所以死锁的危害没有阻塞大.但有时为了解决死锁,会采取对资源加锁,导致阻塞的方式来避免.

  4. hiho一下第76周《Suzhou Adventure》

    我是菜鸡,我是菜鸡,我是菜鸡....重要的事说三遍 算是第一次做树形dp的题吧,不太难.. 园林构成一棵树,root为1,Hi从root出发,有k个园林必须玩,每个园林游玩后会得到权值w[i],最多玩 ...

  5. HTML5动态时钟

    实现效果 源码可以去github下载 地址:https://github.com/feifeiliu/jsBlock 参考:慕课网动态时钟

  6. 使用jQuery对图片进行居中设置

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Static variables in JavaScript

    function MyClass () { // constructor function var privateVariable = "foo"; //NO:obj.privat ...

  8. 使用光盘作为yum源安装ifconfig等网络命令

    # mkdir -p /mnt/cdrom# 如果是光驱:mount -t iso9660 /dev/cdrom /mnt/cdrom/# 如果是ISO:mount -o loop /usr/loca ...

  9. 巧用Ajax的beforeSend提高用户体验

    jQuery是经常使用的一个开源js框架,其中的$.ajax请求中有一个beforeSend方法,用于在向服务器发送请求前执行一些动作. $.ajax({ beforeSend:function(){ ...

  10. 00--Qt Creator 你必须要掌握的快捷操作

    Qt Creator 你必须要掌握的快捷操作 多使用快捷键能显著提高工作效率,尽可能减少键盘,鼠标之间切换所浪费的时间.我这里列出个人认为非常重要必须掌握的 Qt Creator 快捷键.看你知道几个 ...