简介C/C++预处理器的一些工作
多么令人愉快的一个问题啊
就在被带到编译器那里之前,预处理器都会对你的源代码瞧上一瞧, 做一些格式化的工作,并执行任何你在源代码里面留给它来执行的指令.
像什么?
好吧,预处理器的指令就被叫做预处理器指令,而他们都以一个#开头.
像 #include 这样?
正确.
每一个被预处理器遇到的 # 命令都会导致在某种方式上对源代码的修改. 让我们来简单的研究研究它们,然后我们就会之后这背后都是怎么运转的了.
#include
包含其他库、类、接口等的头文件。预处理器实际上就只是把整个头文件复制到你的源代码里面 (是的,这就是包含防御之所以是件好事的原因了).
#define
谁会不喜欢宏呢! 预处理器会把所有定义的实体替换成被定义的代码. 定义会一直持续直到发现这个定义的 #undef 指令.
#ifdef
条件行为告诉预处理器包含在遇到声明的条件成立的条件块中的代码. 你可以就像if-else语句一样使用它们,从这里面选择: #ifdef, #ifndef, #if, #else, 以及 #elif, 而你总是要使用一个 #endif 作为结束。
#error #warning
用来向用户发送消息。预处理器会在 #error 处, 而不会在 #warning 处停下来. 两种情况下他都会发送他在指令背后(的括号里面)发现的字符串, 发送到屏幕作为输出,因此它是一种确保针对你的平台一切OK的手动方式.
#line
用来在你遇到编译错误时修改显示的错误行号和文件名. 例如,加入你需要查看一个来自编译的中间文件的源文件(可能是自动生成的).
#pragma
其它由编译器解释的特殊指令。你的编译器文档会告诉你指令是怎么用的,而你不要假定他们在全世界都通用哦.
#assert #unassert
这些在老程序里面总是特别受欢迎的 (好吧,只要我也曾经为这样一个程序工作过), 但是它们在现在已经过时了。强烈建议不使用它们,这意味着不要把他们放到新的代码里面
预定义宏
有许多可以利用的预定义宏:
__FILE__ 给出一个字符串的文件名
__LINE__ 给出当前的行号(整型)
__DATE__ 当前编译日期的字符串
__TIME__ 当前编译时间的字符串
__STDC__ 同编译器相关的,但常常被定义成1,以声明同ISO C标准兼容.
__cplusplus 在编译一个C++程序是总是会被定义
特别是开头两个在调试时真的非常有用。只要拿出它们俩,不用你自己编写文件和行处理类,就能神奇的让你获得丰富的信息输出.
你的编译器可能还支持其它的宏,例如,你这从 这里 获得(面向GCC)的整个宏清单.
那么当你运行预处理器时实际会发生什么呢?
1. 替换所有的三字母组合,我会在将来的一篇文章中谈论到他,因为尽管他只是一个历史上的特性(而且你也要在GCC中对它进行切换),它仍让是很有趣的.
2. 将并列的源代码分成多行.
3. 移除所有的注释并用一个空格替换.
4. 处理(我们上面讲到的)的预处理器指令。对于 #include, 他会在新文件上递归执行1 - 3步 :-)
5. 处理转义序列.
6. 把文件发送给编译器
如果你想看看预处理之后你的文件会是什么样子 (谁不想呢?),你可以向 gcc 传入 -E 选项. 这将会想stdout标准输出发送预处理过的源代码,并且没有编译和连接就直接终止gcc命令的执行。
例如
g++ -E myfile.cpp
你也可以使用这个参数:
-save-temps
编译的后会有一份临时文件。
拿下面这个简单的程序说吧:
#include <stdio.h> #define ONE 1 #define TWO 2 int main() { printf("%d, %d\n", ONE, TWO); return 0; }
用下面这行命令编译
g++ hello.cpp -save-temps
编译完后, 会在文件夹中生成两个文件: hello.s 和 hello.ii
hello.s 里面是汇编代码, 而 hello.ii 则是预处理过后的源代码。
用文本编辑器打开 hello.ii , 你会发现多出许多代码. 那是因为 #include 指令把 stdio 头文件的代码加进去了。
如果你把滚动条拉到最底下, 就会发现, printf 那一行的宏定义 ONE 和 TWO 已经被预处理器替换成 1 和 2 了 .
神奇吧!
其实它只是在编译的时候, 把你的源代码文件复制一份, 当作临时文件, 然后把里面的预处理指令替换掉. 用完后就把这个临时文件删了. 所以一般情况下我们不知道这个文件的存在.
相关文章
- vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
- 这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
- 整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
- 这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
- 这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
- 这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
- 这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
- 这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
- 虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
- 这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
- 这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
- 这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
- 这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25