C++编译预处理

——C++ " # "的作用和用法


~#和##的作用和用法

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
加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的宏就能得到对应的宏参数。

接下来,我们来了解通过预处理指令创建条件编译参数控制代码编译的一些用法。



~#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文件


~#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!


~#define,#undef,#ifdef,#ifndef用法

1)#define

#define是大家都常见的宏定义方法,用法结构为:
// #define identifier replacement-code
#define PI 3.1415926
#define ADD(x,y) (x + y)

2)#undef

#undef顾名思义,😮就是从该处取消前面已经定义的宏,如果标识符当前没有被定义称为一个宏名称,就会忽略该指令:
// #undef identifier
#undef PI

3)#ifdef 和 #ifndef

#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.    
对于#ifdef——此处定义了宏(#define  DEBUG),则编译相应代码。

#ifndef identifier
#else or #elif
#endif
#define  DEBUG
#ifndef DEBUG
  cout << "This is a debug message." << endl;
#endif

// prints nothing     
对于#ifndef——此处定义了宏(#define  DEBUG),则不编译相应代码。

在编程时,为了避免头文件重定义,经常使用的就是#define配合条件编译解决:
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H

// ...
class MyHeaderFile
{
    // ....
};

#endif // MY_HEADER_FILE_H
除此以外,还有#pragma once的用法,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次。(在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作,本文不多讲述。)


~#line用法

#line命令是用于更改__LINE__ 和 __FILE__变量的值__FILE____LINE__描述被读取的 当前文件 和 所在行数 

// #line line-number filename
int main()
{
#line 10 "main.cpp"
    cout << __FILE__ << " " << __LINE__ << endl;
}
// prints : main.cpp 10


~#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.



——#include< >和#include" " 的区别

#include< >
        #include< > 引用的是编译器的类库路径里面的头文件。
        假如你编译器定义的自带头文件引用在 C:\Keil\c51\INC\ 下面,则 #include<stdio.h> 引用的就是 C:\Keil\c51\INC\stdio.h 这个头文件,不管你的项目在什么目录里, C:\Keil\c51\INC\stdio.h 这个路径就定下来了,一般是引用自带的一些头文件,如: stdio.h、conio.h、string.h、stdlib.h 等等。

#include" "
        #include" " 引用的是你程序目录的相对路径中的头文件。
       假如你的项目目录是在 D:\Projects\tmp\ ,则 #include"my.h" 引用的就是 D:\Projects\tmp\my.h 这个头文件,般是用来引用自己写的一些头文件。如果使用 #include" " ,它是会先在你项目的当前目录查找是否有对应头文件,如果没有,它还是会在对应的引用目录里面查找对应的头文件。例如,使用 #include "stdio.h" 如果在你项目目录里面,没有 stdio.h 这个头文件,它还是会定位到 C:\Keil\c51\INC\stdio.h 这个头文件的。



——#import和#include的区别

#import能避免文件被重复包含的问题

1.🤔一般来说,  导入objective - c 的头文件时用#import——包含c,c++头文件的时候用#include。

使用include时要注意重复引用的问题:

calssA,classB都引用了classC,classD若引用classA与classB,就会报重复使用的错误。

2.#import确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。

所以,#import比起#include的好处就是它避免了重复引用的问题。所以在OC中用得都是#import。

3.#import<>包含IOS框架类库里面的类,#import " "包含项目里自定义的类,

#import ""表示从当前项目路径开始寻找文件,如果找不到,则到系统(项目)中配置的头文件路径去找;

<>表示直接到系统(项目)中配置的头文件路径去找。



全部评论

相关推荐

点赞 1 评论
分享
牛客网
牛客企业服务