C++学习总结
预处理
首先了解一下什么是预处理,C语言的预处理是为了展开头文件/宏替换/去掉注释/条件编译,其主要包含三个方面的内容: 1.宏定义; 2.文件包含; 3.条件编译。 预处理命令以符号“#”开头。
宏定义
不带参数的宏定义:
宏定义又称为宏代换、宏替换,简称“宏”。它的格式:#define标识符文本
。其中的标识符就是所谓的符号常量,也称为“宏名”。预处理(预编译)工作也叫做宏展开:将宏名替换为文本(这个文本可以是字符串、可以是代码等)。掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。即在对相关命令或语句的含义和功能作具体分析之前就要换,例:#define PI 3.1415926
把程序中全部的标识符PI换成3.1415926
特殊说明:
- 宏名一般用大写
- 使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
- 可以用
#undef
命令终止宏定义的作用域 - 宏定义可以嵌套
带参数的宏:
除了一般的字符串替换,还要做参数代换格式:#define 宏名(参数表) 文本
例如:
#define S(a,b)
a*b area=S(3,2);
第一步被换为area=ab; 第二步被换为area=32;类似于函数调用,有一个哑实结合的过程:
(1)实参如果是表达式容易出问题
#define S(r) r*r
area=S(a+b);
第一步换为area=rr;,第二步被换为area=a+ba+b;正确的宏定义是#define S(r) ((r)*(r))
- 宏名和参数的括号间不能有空格
- 宏替换只作替换,不做计算,不做表达式求解
- 函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
- 宏的哑实结合不存在类型,也没有类型转换。
- 宏展开使源程序变长,函数调用不会
- 宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)
常见预处理命令:
其中pragma比较重要,通常使用#pragma(extern "C" )
在C++中来告诉编译器下面是c语言风格。
条件编译
常见的条件编译语句:
#if-#else-#endif
其调用格式为:
#if 条件表达式
程序段1
#else
程序段2
#endif
如下面代码所示:
#define flag 0
#include<stdio.h>
int main(){
#if !flag //条件编译如果
printf("yes");
#else
printf("no");
#endif //标志条件编译的结束
}
#ifndef-#define-#endif
其调用格式为:
#ifndef 标识符
#define 标识符 替换列表
//...
#endif
功能为:一般用于检测程序中是否已经定义了名字为某标识符的宏,如果没有定义该宏,则定义该宏,并选中从 #define 开始到 #endif 之间的程序段;如果已定义,则不再重复定义该符号,且相应程序段不被选中。如果之前定义过了就使用它,忽略 #define 开始到 #endif 之间再次定义的,之前没有定义就使用#define 开始到 #endif 之间的。
#if-#elif-#else-#endif
其调用格式是:
#if 条件表达式1
程序段 1
#elif 条件表达式2
程序段 2
#else
程序段3
#endif
先判断条件1的值,如果为真,则程序段 1 被选中编译;如果为假,而条件表达式 2 的值为真,则程序段 2 被选中编译;其他情况,程序段 3 被选中编译。
头文件包含
一个文件包含另一个文件的内容,格式:
#include "文件名"
或
#include <文件名>
编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。编译以后只得到一个目标文件.obj被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。修改头文件后所有包含该文件的文件都要重新编译头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义:
- 一个#include命令指定一个头文件;
- 文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行;
- 包含可以嵌套;
- <文件名>称为标准方式,系统到头文件目录查找文件,"文件名"则先在当前目录查找,而后到头文件目录查找;
- 被包含文件中的静态全局变量不用在包含文件中声明。
C++基础知识
- 强制类型转换的格式:(typeName) value或typeName (value)。第一种来自C语言,第二种格式的C++。
- const常量被初始化后,其值就固定了,编译器将不允许在修改该常量的值。相比#define,const更好,首先它能够明确指定类型,其次可以使用C++的作用域规则将定义限制在特定的函数或者文件中,其中作用域规则描述了名称在各种模块中的可知程度。第三,可以将const用于更加复杂的类型,如数组和结构。
- 数组:只有在定义数组时才能初始化,此后就不能使用了,也不能将一个数组赋给另一个数组。