突破编程_C++_基础教程(入门程序)

1 程序

如下是一个简单的C++程序,该程序运行后可以在屏幕上打印出"Hello C++!"。

#include 
using namespace std;
int main()
{
	cout << "Hello C++!" << endl;
	return 0;
}

1、程序的第一行

#include 

“#include"是C++预编译器的一种指令,其作用是将指定文件内容复制到当前文件中。因此,一定不能直接include源文件,也就是cpp文件,因为cpp文件中是函数的定义,一旦include了cpp文件,相当于在当前cpp文件又定义了一个相同名字的cpp文件,所以会报错。”#include"后面尖括号中是一个标准库(输入输出流),它包含众多成员函数,比如第四行的 cout 对象,就是其标准库函数的一部分。
使用"#include"指令引入头文件时,包裹头文件的名称可以用尖括号<>,也可以用双引号" "。
例如:

#include 
#include "my_header.h"

如果文件名用尖括号<>括起来,表明这个文件是一个 C++ 标准库中的头文件,编译器会在预定的系统目录中查找该文件。
如果文件名用双引号" "括起来,表明这个文件是用户自己提供的头文件,预编译器会先在当前文件所在的目录中查找,如果找不到,则继续到系统目录中查找。
对于用户自己提供的头文件,必要时可以注明头文件的存储路径,绝对路径和相对路径都可以(也可以定义相应路径到环境变量中)。例如引入 D 盘下的 my_header.h 头文件:

#include "D:/my_header.h"

一般而言,C++ 标准库提供的头文件推荐用尖括号<>,而用户自己定义的头文件推荐双引号" "。

2、程序的第二行

using namespace std;

namespace: 是指命名空间。是C++语言特别重要的特性,当第三方供应商提供的库时,为了避免与其他供应商或者用户定义的名字相冲突(命名空间污染),常常将库的内容放置在自己独立的命名空间中。
std: 是C++标准程序库中定义所有标识符的 namespace。
实际开发过程中,并不建议直接使用"using namespace std",比如以上面的程序为例,如果自己需要定义一个变量:

int cout=0;

在编译过程中会与 std 命名空间的cout输出流重名,会报出 cout 二义性的错误。
因此,建议在使用 cout 对象时,使用完整的 std::cout 。

3、程序的第三行

int main()

main函数是C++程序的入口函数,C++标准规定main()函数的返回值类型为int(虽然在一些编译器中,void main() 可以通过编译,但并非所有编译器都支持 void main()),main()函数返回值用于表示程序的退出状态,如果返回0则表示程序正常退出,如果返回非0,则表示出现异常。C++标准规定,main()函数原型有两种:

int main();
int main(int argc, char* argv[]);
//或者
int main(int argc, char** argv);

如果 main 函数的最后没有写 return 语句的话,C99 和c++89都规定编译器要自动在生成的目标文件中加入return 0,表示程序正常退出。

  • 在 main 函数执行之前,程序会执行以下类型的代码:
    (1)全局对象的构造函数会在main 函数之前执行。
    (2)一些全局变量、对象和静态变量、对象的空间分配和赋初值就是在执行main函数之前,而main函数执行完后,还要去执行一些诸如释放空间、释放资源使用权等操作
    (3)进程启动后,要执行一些初始化代码(如设置环境变量等),然后跳转到main执行。全局对象的构造也在main之前。
    (4)通过关键字attribute,让一个函数在主函数之前运行,进行一些数据初始化、模块加载验证等。
  • 在 main 函数执行结束之后,程序会执行以下类型的代码:
    (1)全局对象的析构函数会在main函数之后执行。
    (2)用atexit注册的函数也会在main之后执行。

4、程序的第五行

cout << "Hello C++!" << endl;

cout 是一个预定义对象,用于显示字符串、数字以及单个字符等。cout 的对象属性包括一个插入运算符(<<),它可以将其右侧的信息(“Hello C++!” )插入到输出流中。endl 是一个特殊的C++符号,用于重启一行。类似 endl 等对于cout来说有特殊含义的特殊符号被称为控制符(manilupator)。和 cout 一样,endl 也是在头文件 iostream 中定义的,且位于命名空间 std 中。

2 编译流程

C++是一种编译语言,这意味着要想使一个程序可以运行,首先必须将其从源代码转换为可执行代码(也可以称为目标代码或机器代码)。这个转换过程由编译器来做。典型的C++源代码文件的后缀为.cpp(例如hello.cpp),目标代码文件的后缀为.obj(在Windows中)或.o〈在Linux中)。
其具体编译流程如下:
预处理->编译->汇编->链接

2.1 预处理

这一步由预处理器完成,对源程序中的伪指令(以#开头的指令,如#include、#define、#if等)和特殊符号进行处理,经过预处理阶段,将产生一个没有注释、include、宏定义、条件编译等指令的.i文件。这一步的主要工作包括以下内容:
1、将所有的#define删除,并将宏定义进行宏展开。
2、处理所有的注释(包括单行与多行注释),将注释替换为空格。
3、处理所有条件编译指令,如#if、#ifdef、#ifndef、#else、#elif、#endif等,预处理将其删除,并直接返回条件满足的结果。
4、处理#include,删除#include语句,将include的头文件包含进来,该头文件被包含到.i文件中,与.cpp文件的内容拼接在一起。如果是多重包含的话会递归执行。
5、添加行号和文件标识,以便于编译时编译器产生调试用的行号信息及编译时产生编译错误和警告时可以把行号打印出来。(#line的用法一般为 #line 行号 filename,用于强制编译器按指定的行号,开始对源程序的代码重新编号,在调试的时候,可以按此规定输出错误代码的准确位置)
6、保留#pragma编译器指令(非预编译指令),该指令用于设置编译器状态或指示编译器完成一些特定的动作。(常见的#pragma用法有#pragma once、#pragma message等)
7、处理预定义的宏:如__DATE__、__FILE__等。
以样例代码 hello.cpp 为例,第一行的#include 命令告诉预处理器读取系统头文件iostream.h的内容,并把它直接插入到程序文本中,结果就得到了另一个cpp程序,通常是以.i作为文件扩展名。

2.2 编译

这一步由编译器完成,对预处理后的文件进行词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言的程序。
具体步骤如下:
1、词法分析:将源代码分解成一个个的单词,并检查语法错误,如拼写错误、未定义的变量等。
2、语法分析:根据 C++ 的语法规则,检查源代码是否符合语法规范。
3、语义分析:检查源代码中的变量、函数等是否正确声明和使用。
4、生成中间代码:将源代码转换成一种中间表示形式,通常是汇编语言或机器码的一种抽象形式。
5、优化:对中间代码进行优化,以提高程序的运行效率。

2.3 汇编

将编译完的汇编代码文件翻译成机器指令,并生成可重定位目标程序的.o文件,该文件为二进制文件,字节编码是机器指令。
汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译即可。

2.4 链接

编译步骤得到各个模块的二进制码,但各个模块之间仍然存在引用调用关系,这时就得链接步骤去解决,链接步骤就是将各种模块合成一个完整的可执行程序文件。链接步骤由链接器程序来实现,它将编译得到的目标文件合并成可执行目标程序。
具体步骤如下:
1、符号解析:将目标文件中的符号(如函数、变量等)与其他目标文件或库文件中的符号进行关联,以确定它们之间的调用和引用关系。
2、地址重定位:根据连接后的程序结构,为每个符号分配具体的内存地址。
3、构建可执行文件:将目标文件和所需的库文件链接起来,生成一个可执行文件。

你可能感兴趣的:(突破编程_C++_基础教程,c++,java,jvm)