C++学习笔记(1):C++编程基础

C++程序结构

主函数

C++程序包含一个或多个函数,其中必须包括一个主函数,主函数是程序运行的入口。对于主函数,结构如下:

C++规定主函数返回值类型应当为int,且其返回值通常用来表示程序的运行状态,如:0代表程序正常结束,1代表出现了异常(或用若干非0值表示不同种类的异常)。
函数体是该函数的具体内容,实际为由一对花括号表示的代码块。

编译、运行程序

C/C++程序的编译过程

直接由程序员编写的C++程序的源代码文件命名为*.cpp,C语言源代码文件则为*.c,最终我们需要得到*.exe文件(Windows下)才可以执行C/C++程序。该过程分为以下几个步骤:

预处理

处理前:*.cpp ;处理后:*.i/*.cpp 。
预处理是对源代码进行初步处理的过程,按照程序员编写在源代码中的以“#”开始的预处理指令(伪指令),对源代码进行分隔或处理成特殊的符号,这一过程实质为单纯的文本替换,并不对源代码进行解析。
预处理可执行的操作一般包括文件包含、条件编译、布局控制和宏替换等。
经过预处理得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main, if , else , for , while , { , } , + , - , * , \ 等等。

编译

处理前:*.i/*.cpp ;处理后: *.s 。
编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码的过程。

汇编

处理前: *.s ;处理后: *.o/*.obj 。
汇编过程实际上就是把汇编语言代码翻译成目标机器指令的过程。
对于被翻译系统处理的每一个C/C++语言源程序,都将最终经过这一处理而得到相应的目标文件。即:多文件项目的每个源文件都将生成目标文件。目标文件中所存放的也就是与源程序等效的机器语言代码。

链接

处理前: *.o/*.obj ;处理后: *.exe/*.elf/*.axf 等 。
由汇编程序生成的目标文件由于引用问题而不能立即就被执行,主要包括以下两个方面的引用问题:
① 某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);
② 在程序中可能调用了某个库文件中的函数。
链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,成为可执行的文件。

编译、汇编与链接

编译

在编译的同时往往需要进行优化,优化处理是编译系统中一项比较艰深的技术。
它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。
第一种优化是对中间代码的优化,这种优化不依赖于具体的计算机,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除等等;另一种优化则主要针对目标代码的生成而进行的,它同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放有关变量的值,以减少对于内存的访问次数。
此外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。

汇编

目标文件由段组成。通常一个目标文件中至少有两个段:
代码段:该段中所包含的主要是程序的指令,一般是可读和可执行的,但一般不可写。
数据段:主要存放程序中要用到的各种全局变量或静态的数据,一般数据段都是可读、可写、可执行的。
汇编程序生成的实际上是“可重定位文件”:包含有可配合其它目标文件进行链接来创建一个可执行的或者共享的目标文件的代码和数据。

链接

根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
静态链接:函数的代码将从其所在的静态链接库中被拷贝到最终的可执行程序中,这样这些引用的代码就成为了程序的一部分,该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。其中静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中,链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间,动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
对静态链接在每个调用位置都将有一个代码副本,这样带来的后果是占用了更多空间,但是在使用这些代码时直接就能使用而不用寻找,在性能上更加优越。动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件,这样多次调用的代码不会在内存中存在很多副本,节省了内存空间,并且分模块的方式使得程序更新容易。

输入、输出

IO标准库

C++语言的输入输出通过标准库iostream来实现。
iostream包含两个基础类:输入流istream和输出流ostream。
“流”代表字符是顺序产生和消耗的。

标准输入输出对象

标准库iostream定义了四个标准输入输出对象,分别是:

对象 名称 类型
cin 标准输入 istream
cout 标准输出 ostream
cerr 标准错误输出 ostream
clog 日志输出 ostream

系统通常将程序所运行的窗口与这些对象关联起来。因此,当我们读取cin时,数据将从程序正在运行的窗口读入,当我们向cout、cerr和clog写入数据时,将会写到同一个窗口(程序运行窗口)。

使用输入输出对象

① cin和cout等属于标准库iostream中提供的名称,要使用这些名称,首先要引入iostream库:

1
#include<iostream>

在引入标准库时使用尖括号包含头文件,并省略“.h”后缀,若使用自己编写的头文件,则使用双引号包含头文件,这样将告知编译器同时在项目目录和系统目录中查找头文件。
② 使用标准库中的名称时,要表明该名称来自于标准库的命名空间,因此需要使用std::cin和std::cout而不是直接使用它们。或者还可以直接在程序开始时声明默认使用的命名空间:

1
using namespace std;

③ 向流写入和读出数据使用重载的“<<”“>>”运算符来实现,如:

1
2
3
cout<<"Enter two numbers:";
cout<<endl;
cin>>a>>b;

无论是重载的左移运算符还是右移运算符,均为从左到右的结合方向,并且运算后的内容依然是cin或cout,因此运算符可以连续使用,即:

1
2
3
cout<<"Enter two numbers:";
cout<<endl;
cin>>a>>b;

等价于

1
2
3
cout<<"Enter two numbers:"<<endl;
cin>>a;
cin>>b;

特殊地,当已经无内容可读时(遇到文件尾EOF)或无效输入时,cin>>a将返回NULL,因此可以通过此来读取任意数量的数(但需要手动输入EOF,Windows下即Ctrl+Z)。
④ 标准库iostream中还提供了一些其他的名称可供使用,如

1
cout<<endl;

将输出一个换行符。

注释

注释及分类

编译器对于注释将直接忽视,注释的作用仅仅是帮助程序员理解代码,对于程序的功能和性能均无任何影响。
C++的注释分为行注释块注释

注释的规则

行注释是以 // 开始的,在此之后到该行末尾的所有内容均会被注释。
块注释是以 /* 开始,并以 */ 结束的注释,在此之间所有的内容均会被注释掉。
块注释的判定是非贪心的,也就是在 /* 之后遇到的第一个 */ 会被当成结束符,因此块注释无法嵌套(当然嵌套的注释也没有什么实际意义)。

自定义类

C++与C语言最大的区别就是面向对象的特性,类与对象是面向对象程序设计中的重要概念。
类与对象的关系为:对象是类的实例,类是对象的类型。
在C++中许多标准库提供了许多有用的类,同时开发者也可创建属于自己的类,并为类设计合适的成员变量和成员函数,使其发挥应有的作用。
在编写自定义类时,往往将类的声明写在单独的一个头文件中,头文件使用类名来命名;并将类定义写在源文件中,同样使用类名来命名。如:类MyString应对应两个文件,分别是包含声明的MyString.h文件和包含定义的MyString.cpp文件。




* 你好,我是大森。如果文章内容帮到了你,你可通过下方付款二维码支持作者 *