C++项目生成四个基本过程及重定义与重复包含ERROR

一 项目生成四个基本过程


c++项目生成可以分为四个过程:预处理,编译,汇编,链接。
各个过程需要完成的任务如下:
①预处理【.cpp+.h—>.i】:宏替换(将eg #define PI 3.14 之类的宏定义进行替换)/去注释(字面意思)/条件编译(eg #ifndef… #define…#endif)/头文件包含(在.cpp中将其包含的头文件的内容复制进来)
②编译【.i—>.s】:以单个文件为单位进行语法检查,将其生成汇编文件(ASCII码文件)。
③汇编【.s—>.o】:以单个文件为单位,将其生成机器码(CPU可以执行的机器指令)。
④链接【.o—>.exe】:将所有的.o文件进行链接,生成可执行的.exe。

二 重定义与重复包含ERROR


我们通常通过在头文件声明#pragma once或者#ifndef…#define…#endif 来避免因为重复包含造成的变量重定义,但是这并不能完全避免变量的重定义。

换句话说,其只能解决单个.cpp文件因为重复包含同一个头文件造成的重定义。看上面c++项目生成过程,在预处理阶段(至汇编阶段),编译器会以单个.cpp为单位,对项目进行初步生成。其步骤有将.cpp包含的.h文件复制到进来。如果,在这过程中出现了.h被重复包含的情况,.h文件则会被重复复制,.h中定义的变量也将会被重复的复制,那肯定会报重定义。而#pragma once或者#ifndef…#define…#endif 可以使得在复制过程进行之前进行判断:你是不是复制过了?如果复制过,就不进行再次复制,从而也就避免了重复定义。

但是,如果多个.cpp文件中都包含了相同的.h文件,即每个.cpp中都有了该变量的定义,则在链接的时候,所有.cpp文件相关联,自然会出现变量的重读定义。

最好的解决方法自然是不要将变量的定义放在.h中。更确切的说,不要将占内存的数据定义(变量定义,对象定义,函数实现…)放在.h中,可以将不占内存的类型定义(函数声明,结构体/类的声明…)放在.h中。

三 #pragma once和#ifndef...#define...#endif区别

#pragma 指令用于设定编译器的状态或者是指示编译器完成一些特定的动作。所以#pragma once和编译器相关,它可以让同一个.h头文件不被包含多次。其缺点是移植性差,在当前编译器上可用不一定能在其它编译系统上用【当然,现在的编译器大部分都兼容了,但是以前的一些老旧的编译器许多不支持】。此外,“同一个.h头文件”指的是物理上的同一个文件,而不是指内容相同的两个文件。即如果有内容相同的两个文件,#pragma once不起作用。

相比较而言,#ifndef…#define…#endif是C++语言相关,它属于C++语言中的宏定义。所以其可移植性好,即在所有支持C++语言的编译器上都是有效的(可以跨平台应用)。此外,它可以保证内容完全相同的而名字不同的文件不被包含(前提是#ifndef后面跟着的宏是一样的,即内容完全相同但是名字不同的头文件有着相同的#ifndef宏)。缺点就是如果不同头文件定义了相同的宏,则可能导致意外的冲突——找不到头文件。

你可能感兴趣的:(编程小知识)