目录
Part 01 Welcome to C++
1.为什么学习C++——写高性能代码的选择
①直接内存控制
② 低级别访问
③性能优化工具
④内联汇编
⑤ 多范式编程
2.C++的可移植性和高效性
2.1 可移植性
2.2 高效性
Part 02-Part 04
1.在不同环境中安装C++编译器
2.新建源文件
Part 05 How C++ Works
1.Hello World
2.从文件到可执行程序
2.1预处理
2.2编译
2.2.1 配置方式
编辑编辑2.2.2 Object文件(目标文件)
2.2.3 编译错误
2.3链接
2.3.1 链接过程
2.3.2 链接错误编辑
注意:编译器只关注当前文件的代码,并不会检查函数的实际定义是否存在于其他文件中
体现在以下的几个方面:
C++允许程序员直接管理内存,这使得可以更有效地利用系统资源,避免不必要的开销。
C++提供了对硬件和底层系统的低级别访问,使得程序员可以更精细地控制代码的执行,以实现最佳性能。
C++有丰富的性能优化工具和库,如编译器优化、多线程支持和标准模板库(STL),有助于开发者编写高效的代码。
C++支持内联汇编,允许在代码中嵌入汇编语言,进一步提高性能。
C++支持多种编程范式,包括面向对象编程和泛型编程,使得开发者能够选择最适合其需求的编程方式。
C++写好代码,交给编译器,编译器为你的目标平台生成可执行的机器码(机器码由二进制的0和1组成。机器码是计算机硬件可以直接执行的指令,而这些指令以二进制形式表示。每个二进制位(0或1)代表机器指令的一部分,从而构成完整的机器码)
所以针对不同的平台生成的机器码是不一样的,所以C++具有可移植性。
而相比C#和Java这种同样可移植的编译型语言,C++的高效性是怎么体现的呢?
在不同的操作系统运行C#的时候,C#代码会被编译成中间语言(这个中间语言是跟平台无关的,类似于汇编语言的低级代码),生成IL文件,然后再由IL编译器转化为二进制的机器码。
Java的编译规程与C#类似,Java源代码被Java编译器编写成字节码(同样与平台无关,类似于汇编语言)然后再由JVM(Java虚拟机)将字节码编译成本地机器码。
我们可以这样理解,你写了一本汉语书,然后想要在美国出版,我们会采用直接翻译成英文的方法,而不是再配备一个翻译工具,看的时候再用工具翻译成英语。
所以我们对比C++可以发现,C++省去了中间环节,会更加高效。
但是需要注意,这种高效是体现在你写的代码非常的好,不然效率还是很低。简单来说,C++的上限很高,但是下限取决于你写的代码。
这个与C语言过程中所用的编译器一样
#include
int main()
{
std::cout << "Hello World!" << std::endl;
std::cin.get();
}
逐行分析
#include
//#之后称为预处理语句
//编译器收到文件以后,第一件事就是处理预处理指令
//这个过程发生在真正的编译之前
//include 说明它需要先找一个名叫iostream的文件
//然后将内容拷贝到目前这个文件里
//这里的文件称为头文件
//我们之所以需要拷贝这个iostream文件是因为我们后面cout和cin指令定义在这个文件里
int main()
//程序的入口,有且仅有一个
//程序运行时从这里开始执行代码
//代码是逐行执行的
// (尽管我们可以是使用控制流语句或其他函数改变,但是微观上说,还是一条一条语句走下去的)
//int 代表函数的返回值
//main 函数比较特殊,不一定需要返回值
//默认返回0
std::cout << "Hello world!" << std::endl;
//标准库是C++语言提供的一组常用功能和数据结构的集合(跟C语言一样)
//它包含了许多不同的类、函数和对象,用于各种编程任务,如输入输出、容器操作、算法等
//std:;是函数的前缀,明确指定你使用的是标准库的成员
//为了避免与其他可能存在的同名对象或函数发生冲突
//cout C++ 标准库中的输出流对象,可以理解成C+out
//在程序中将数据输出到标准输出设备,通常是控制台
<<
//在这里<<(左移运算符)被重载,用于将数据插入到输出流中
//重载指的是,相同的符号在不同的情况有着不同的用法
//可以把重载理解为“变身”
//重载允许同一个名称的函数或运算符根据不同的参数类型或数量拥有不同的行为
//这就好像同一个名字的实体在不同的上下文中有着不同的角色或功能
//endl 操作符
//可以理解成end+line 作用与C语言中的换行符\n类似
std::cin.get();
//cin 是 C++ 标准库中的输入流对象
//用于从标准输入设备(通常是键盘)读取数据
//get() 是 C++ 标准库中用于从输入流(通常是键盘或文件)读取单个字符的成员函数
//get() 会读取包括空格和换行符在内的所有字符,直到用户按下 Enter 键
//在这里其实就是为了让程序停下,我们按任意键+Enter,程序会接着往下执行
//因为后面没有任何东西,所以程序结束
#之后称为预处理语句,在我们这个程序中首先会把iostream文件里的所有内容拷贝到我们编写代码的这个文件当中,就是简单的复制粘贴
编译器会把我们的C++代码转化为机器码
针对Windows系统下的VS2022 ,我们详细说一下,在菜单栏我们会看到两个可供我们选择的东西,默认是Debug和x86
左边是方案配置:有两种配置方式
Debug调试配置
Release发布配置
右边是平台配置:有两种配置方式
指的是我们代码的目标平台,就是说我们想要在什么操作系统中运行我们的可执行程序
x86指的是32位操作系统
x64指的是64位操作系统
手动更改这些信息
在这里我们可以更加直观的感受到Debug和Release的区别
每一个.cpp文件会被编译object文件(目标文件),扩展名是.obj
按Ctrl+F7:单独编译一个cpp文件
我们打开刚才放代码的文件夹还会找到obj文件
刚才我们的只有一个cpp文件,如果有多个呢,该怎么办呢
我们将刚才的代码改一改,改成两个文件
//Main.cpp 文件
#include
void Log(const char* message);
int main()
{
Log("Hello World!");//用Log函数实现打印的功能
std::cin.get();
}
//Log.cpp 文件
#include
void Log(const char* message)
{
std::cout << message << std::endl;
}
这里的函数声明和定义跟C语言一模一样,就不再赘述。
然后我们点击Ctrl+F5运行,在这个过程中,每个cpp文件都会被编译成obj文件,然后链接器会将几个obj文件链接为一个exe文件
这个时候我们就会得到链接错误
因为我们在编译完每个文件的以后,会取找我们调用的函数Log是怎么定义的,结果没找到
在这里我们看一个好玩的现象
如果我们把Main函数里面的声明改一改,改成另一个函数,单独编译,我们来看一下效果
Crtl+F7单独编译这个文件
成功的!
在 C 或 C++ 编程中,单独编译一个文件时,即使只有函数声明而没有实际的函数定义,通常是可以成功编译的。这是因为在编译阶段,编译器只关注当前文件的代码,并不会检查函数的实际定义是否存在于其他文件中。编译器只需要知道函数的声明以进行语法检查,而函数的实际实现可以在链接阶段或者在后续编译单元中提供。