C++ "#"的作用和使用方法

时间:2023-03-08 23:19:28
C++ "#"的作用和使用方法


本系列文章由 @yhl_leo 出品,转载请注明出处。

文章链接: http://blog.****.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.