转载请保留: http://www.cnscn.org(CNS电脑与英语学习网)

Author: cnscn http://www.cnscn.org

1)预处理

根据已放置在文件中的预处理指令来修改源文件的 内容

预处理器会分析\执行所有的预处理器指令,然后删除他们,得到一个仅包含C++语句的转换单元

预处理指令以#号开头

常用的预处理指令:

include 包含头文件

if 条件

else 否则

elif 否则如果

endif 结束条件

ifdef 或 #if defined 如果定义了一个符号, 就执行操作

ifndef 或 #if !defined 如果没有定义一个符号, 就指执行操作

define 定义一个符号

undef 删除一个符号

line 重新定义当前行号和文件名

error 输出编译错误 消息, 停止编译

pragma 提供 机器专用的特性,同时保证与C++的完全兼容

2)#include  在 程序中包含头文件

 头文件通常以.h结尾,其 内容可使用#include预处理器指令包含到 程序中

 头文件中一般包含: 函数原型与全局变量

形式常有下面两种

include

include "myheader.h"

前者<>用来引用标准库头文件,后者""常用来引用自定义的头文件

前者<>编译器只搜索包含标准库头文件的默认 目录,后者首先搜索正在编译的源文件所在的 目录,找不到时再搜索包含标准库头文件的默认 目录.

如果把头文件放在其他 目录下,为了查找到它,必须在双引号中指定从源文件到头文件的完整路径

3)#define 定义符号、宏

1>符号

define PI 3.1415925 定义符号PI为3.1415925

define PI      取消PI的值

这里PI看起来像一个变量,但它与变量没有任何关系,它只是一个符号或标志,在 程序代码编译前,此符号会用一组指定的字符来代替

3.14159265 不是一个数值,只是一个字符串,不会进行检查

在编译前,预处理器会遍历代码,在它认为置换有意义的地方,用字符串PI的定义值(3.14159265)来代替

 在注释或字符串中的PI不进行替换

在C中常以#define来定义符号常量,但在C++中最好使用const 来定义常量

define PI 3.14159265

const long double PI=3.14159265;

两者比较下,前者没有类型的指定容易引起不必须的麻烦,而后者定义清楚,所以在C++中推荐使用const来定义常量

 #define的缺点:

1)不支持类型检查

2)不考虑作用域

3)符号名不能限制在一个命名 空间中

2>#undef 删除#define定义的符号

define PI 3.14159265

... //之间所有的PI都可以被替换为3.14159265

undef PI

之后不再有PI这个标识符

3>定义宏

define Print(Var) count<<(Var)<<endl

用宏名中的参数带入语句中的参数

宏后面没有;号

Print(Var)中的Print和(之间不能有空格,否则(就会被解释为置换字符串的一部分

define Print(Var, digits) count << setw(digits) << (Var) << endl

调用

Print(ival, 15)

预处理器就会把它换成

cout << setw(15) << (ival) << endl;

所有的情况下都可以使用内联函数来代替宏,这样可以增强类型的检查

template inline void Print (const T& var, const int& digits)

{

count<<setw(digits)<<var<<endl;

}

调用

Print(ival, 15);

使用宏时应注意的易引起的错误:

define max(x,y) x>y?x:y;+

调用 result = max(myval, 99); 则换成 result = myval>99?myval:99; 这个没有问题是正确的

调用 result = max(myval++, 99); 则换成 result = myval++>99?myval++:99; 这样如果myval>99那么myval就会递增两次,这种情况下()是没什么用的如result=max((x),y)则 result = (myval++)>99?(myval++):99;

再如

define product(m,n) m*n

调用

result = product(5+1,6);则替换为result = 5+1*6; 所以产生了错误的结果,此时应使用()把参数括起

define product(m,n) (m)*(n)

则result = product(5+1,6);则替换为result = (5+1)*(6); 所以产生了错误的结果,此时应使用()把参数括起

结论: 一般用内联函数来代替预处理器宏

技巧:

1)给替换变量加引号

#define MYSTR "I love you"

cout << MYSTR ; //I love you而不是"I love you"
如果
cout << "MYSTR" ; //则会输出"MYSTR"而不是"I love you" 可以这样做
cout << #MYSTR ; //则会输出 "I love you"即cout << "\"I love you\""; 2)在宏表达式中连接几个参数

#define join(a,b) ab 这样不会理解为参数a的值与参数b的值的连接,即如join(10,999)不会理解为10999而是把ab理解为字符串,即输出ab
这时可以
#define join(a,b) a##b
则join(10,999)就会输出10999

3)逻辑预处理器指令

 #if defined CALCAVERAGE 或 #ifdef CALCAVERAGE

int count=sizeof(data)/sizeof(data[0]);

for(int i=0; i<count; i++)

average += data;

average /= count;

endif

如果已经定义符号CALCAVERAGE则把#if与#endif间的语句放在要编译的源代码内

防止重复引入某些头文件

ifndef COMPARE_H

define COMPARE_H 注意: 这里只是定义一个没有值的符号COMPARE_H, 下面的namespace compare不是COMPARE_H的 内容,这里的定义不像是定义一个常量或宏,仅仅定义一个符号,指出此符号已定义,则就会有下面的 内容namespace compare{...

namespace compare{

double max(const double* data, int size);

double min(const double* data, int size);

}

endif

比较

define VERSION \

3

因为有换行符\ 所以上句等价于 #define VERSION 3

由此可以看出#define COMPARE_H与namespace compare是独立没有关系的两个行

也可以这样用

if defined block1 && defined block2

...

endif

if CPU==PENTIUM4

...

endif

if LANGUAGE == ENGLISH

define Greeting "Good Morning."

elif LANGUAGE == GERMAN

define Greeting "Guten Tag."

elif LANGUAGE == FRENCH

define Greeting "Bonjour."

else

define Greeting "Hi."

endif

std::cout<<Greeting << std::endl;

if VERSION == 3

...

elif VERSION == 4

...

else

...

endif

5)标准的预处理器宏

LINE 当前源文件中的代码行号,十进制整数

__FILE__  源文件的名称,字符串字面量

__DATE__  源文件的处理日期,字符串字面量,格式mmm dd yyyy其中mmm是月份如Jan、Feb等 dd是01-31 yyyy是四位的年份

TIME 源文件的编译 时间,也是字符串字面量格式是hh:mm:ss

STDC 这取决于实现方式,如果编译器选项设置为编译标准的C代码,通常就定义它,否则就不定义它

__cplusplus 在编译C++ 程序时,它就定义为199711L

使用#line可以修改__FILE__返回的字符串

line 1000 把当前行号设置为1000

line 1000 "the program file" 修改__FILE__返回的字符串行号改为了1000,文件名改为了"the program file"

line LINE "the program file" 修改__FILE__返回的字符串行号没变,文件名改为了"the program file"

cout << "program last complied at "<<TIME

<< " on " << DATE

<< endl;

6)#error

在预处理阶段,如果出现了错误,则#error指令可以生成一个诊断 消息,并显示为一个编译错误,同时中止编译

ifndef __cplusplus

error "Error - Should be C++"

endif

7)#pragma

 专门用于实现预先定义好的选项,其结果在编译器说明文档中进行了详细的解释。编译器未识别出来的#pragma指令都会被忽略

8)assert()宏

在标准库头文件中声明

用于在 程序中 测试一个逻辑表达式,如果逻辑表达式为false, 则assert()会终止 程序,并显示诊断 消息

用于在条件不满足就会出现重大错误,所以应确保后面的语句不应再继续执行,所以它的应用非常灵活

注意: assert不是错误处理 机制,逻辑表达式的结果不应产生负面效果,也不应超出 程序员的控制(如找开一个文件是否成功), 程序应提供适当的代码来处理这种情况

 assert(expression);

assert(expression) && assert(expression2);

可以使用#define NDEBUG来关闭断言 机制

include

include

using std::cout;

using std::endl;

int main()

{

int x=0;

int y=0;

 cout<<endl;

 for(x=0; x<20; x++)
{
cout<<"x= "<<x <<" y= "<<y<<endl;
assert(x<y); //当x>=y与x==5时,就报错,并终止 程序的执行
}
return 0;

}

【C++】预处理过程与语句总结的更多相关文章

  1. 时间序列预测——深度好文,ARIMA是最难用的(数据预处理过程不适合工业应用),线性回归模型简单适用,预测趋势很不错,xgboost的话,不太适合趋势预测,如果数据平稳也可以使用。

    补充:https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-15-276 如果用arima的话,还不如使用随机森 ...

  2. PHPmysqli的 预处理执行插入语句

    预编译在mysql端 预编译可以自动防止sql注入攻击 <?php //预编译技术 //1.创建一个mysqli对象 //2.创建myslqi预编译对象 $mysqli=); $mysqli-& ...

  3. 前端学PHP之PDO预处理语句

    × 目录 [1]定义 [2]准备语句 [3]绑定参数[4]执行查询[5]获取数据[6]大数据对象 前面的话 本来要把预处理语句和前面的基础操作写成一篇的.但是,由于博客园的限制,可能是因为长度超出,保 ...

  4. PHP基础知识之————PDO预处理语句

    转载处:http://www.cnblogs.com/xiaohuochai/p/6133353.html 定义 在生成网页时,许多PHP脚本通常都会执行除参数之外,其他部分完全相同的查询语句,针对这 ...

  5. c语言编译预处理和条件编译执行过程的理解

    在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令.预处理命令属于C语言编译器,而不是C语言的组成部分.通过预处理命令可扩展C语言程序设计的环境. 一.预处理的工作方式 1.1. ...

  6. mysql -- 预处理语句

    所谓预处理,即在真正执行某条SQL语句之前,先将SQL语句准备好,在执行过程中再绑定数据 语法: 准备预处理 prepare 预处理名字 from ‘要执行的SQL语句’ 执行预处理 execute ...

  7. 深入学习MySQL 01 一条查询语句的执行过程

    在学习SpringCloud的同时,也在深入学习MySq中,听着<mysql45讲>,看着<高性能MySQL>,本系列文章是本人学习过程的总结,水平有限,仅供参考,若有不对之处 ...

  8. C/C++预处理指令#define,#ifdef,#ifndef,#endif…

    2016年12月29日更新: 今天查看以前文件的时候, 突然发现了#error 这个预处理指令.然后回想一下工作, 发现这个指令使用场景还是很多的.比如: 一个项目的模块儿之多,源文件之大,代码之多, ...

  9. C程序编译过程浅析

    前几天看了<程序员的自我修养——链接.装载与库>中的第二章“编译和链接”,主要根据其中的内容简单总结一下C程序编译的过程吧. 我现在一般都是用gcc,所以自然以GCC编译hellworld ...

随机推荐

  1. 27.Docker集群部署

    对于scrapy的部署方式 1.Scrapyd 安装扩展组件,远程控制scrapy任务,包括部署源代码,启动任务,监听任务.scrapy-client .scrapyd api 协助完成部署和监听操作 ...

  2. spark快速大数据分析

    从上层来看,每个Spark 应用都由一个驱动器程序(driver program)来发起集群上的各种并行操作.驱动器程序包含应用的main 函数,并且定义了集群上的分布式数据集,还对这些分布式数据集应 ...

  3. Feign 的简单使用(2)

    依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>sp ...

  4. [记录] 解决img的1px空白问题

    第一种解决方案:把img变成块元素:display:block: 第二种解决方案:修改一下它的垂直对齐方式:vertical-align:middle: 第三种解决方案:使用浮动,让他漂浮起来:flo ...

  5. TP5 模型事务操作

    注意:数据只要涉及多表一致性操作,必须要开启数据库事务操作 ThinkPHP5 中模型层中使用事务: try{ $this->startTrans(); $this->data($orde ...

  6. js对象引用和赋值

    体验更优排版请移步原文:http://blog.kwin.wang/programming/js-object-reference-assign.html 先看一个简单例子, var obj = { ...

  7. eclipse,import,导入项目显示红色叹号

    [场景]eclipse导入项目后,该项目出现红色叹号.打开类文件,会有无数的“The type ... cannot be resolved.”等稀奇古怪的编译错误. [分析]当前eclipse环境中 ...

  8. pandas 笔记

    删除: del df["A"]  # 原地修改 df.drop("a")  # 返回修改后的新对象 df.drop(["a", " ...

  9. js 迭代 方法

    在js 中,有一些方法, 可以很方便的遍历出数据,不用进行for循环就可以,是怎么实现的呢? 例如:在javascript 中的forEach 方法:打印一个数组的索引和项目: 1. forEach  ...

  10. 【375】COMP 9021 相关笔记

    1. Python 中的逻辑否定用 not 2. 对于下面的代码直邮输入整数才能运行,无论字符串或者浮点型都会报错 int(input('How many games should I simulat ...