河北省网站备案管理系统,网站地图模版,一步一步教你做网站,银川网页设计公司C/C文件C/C程序文件包括 .h .c .hpp .cpp#xff0c;其中源文件(.c .cpp)是基本的编译单元#xff0c;头文件(.h .hpp)不会被编译器编译。C/C项目构建(build)过程#xff0c;分为以下几个步骤 预处理 → 编译 → 链接。预编译预编译的过程可以理解为编译器(实际上是预处理器…C/C文件C/C程序文件包括 .h .c .hpp .cpp其中源文件(.c .cpp)是基本的编译单元头文件(.h .hpp)不会被编译器编译。C/C项目构建(build)过程分为以下几个步骤 预处理 → 编译 → 链接。预编译预编译的过程可以理解为编译器(实际上是预处理器这里统称为编译器就可以了)在正式编译之前处理C/C文件中的预处理命令即#开头的代码。常用的几个预处理命令如下#include ......#ifdef ...... #else......#endif#define ......#pragma ......举个例子下面是个很简单的类定义MyClass.hMyClass.cpp预编译完成后的样子可以看到编译器把.h文件替换到了.cpp文件中的#include 位置上把DEFAULT_VALUE定义的值也替换到了相应的位置。编译预编译之后编译器会编译每个源文件(.c .cpp)如果编译成功会生成对应的目标文件Linux为.o文件Windows平台下为.obj文件。以Linux平台为例上面的MyClass.cpp编译完成后会生成MyClass.o文件使用objdump可以看到目标文件MyClass.o的内容编译器会把MyClass::Fun()的名字改成_ZN7MyClass3FunEv这个过程叫Mangle由于C支持重载覆盖等特性所以编译器必须把函数用一个唯一的标识表示。这个字符串就是编译器生成的唯一标识。这里还要单独说一下头文件头文件的既然不是编译单元那么它的作用是什么头文件就是负责”声明“编译器在编译MyClass.cpp的时候对于MyClass这个类以及Fun()这个成员函数编译器必须找到它的声明这个函数才能被正确编译。如果有其他cpp需要使用MyClass这个类的时候也需要它的的声明。例如main.cpp加上#include MyClass.h 编译器在编译main.cpp的时候才知道怎么编译MyClass这个类。MyClass.h里声明是不会真正被编译到main.o中.h文件中的内容在目标文件中只是以列表的形式存在这个表在后面链接时会用到。当然头文件不仅可以用来声明还可以定义(定义全局变量全局函数等)在头文件中的定义要小心可能会引起链接错误。链接链接就是将一堆目标文件加静态库文件装配成可执行文件的过程。(或者是装配成静态/动态库的过程)上面两个cpp分别被编译成了MyClass.o, 和main.o我们要生成可执行程序的话就必须经过链接的过程把两个目标文件合成一个可执行文件。main.o中main函数会构造MyClass, 并且调用Fun()函数那么main就根据MyClass.h生成的表找到MyClass.o中的函数这个就是链接器要做的工作。常见错误构建c/c工程的时候最常见的就是两种错误-- 编译错误在编译过程中产生的错误通常是语法错误没有声明重复声明导致编译目标文件错误其中没有声明通常是由于没有#include相应的头文件或者头文件缺少相应的声明。而重复声明通常是#include了相同的头文件比如 B.h 和 C.h 都包含 A.h然后 main.h 包含了 B.h 和 C.h这就导致A.h 在main中被包含了两次。解决这个问题的方法是可以在所有.h文件的第一行加上#pragmaonce或者使用#ifndef ... #define ... #endif 语句块-- 链接错误常见的错误也是两种没有定义和重复定义和上面的没有声明重复声明类似。(这里定义指的就是函数实现)先讨论没有定义(undefined reference to xxx)通常是因为函数有声明而且被使用了但是没有被定义。比如上面MyClass.cpp中如果Fun()没有被实现的话MyClass.cpp和main.cpp编译时都不会报错但是链接时会报告找不到Fun()。当然如果Fun()没被main.cpp调用的话即使不实现它整个构建过程也不会出错因为链接器根本不会去找这个函数的定义。然后是重复定义(multiple definition)指的一份相同的定义在两个目标文件中都存在链接的时候链接器不知道时用哪个了。这种问题通常由于全局函数和全局变量定义在了头文件中。导致多个目标文件包含相同的全局函数和全局变量的定义。解决方法就是在头文件中声明定义放到cpp文件中或者为定义加上const 或 static这样的修饰符链接时会对这些带有const和修饰符的变量特殊处理的。const只适用于定义常量变量static定义的是静态全局变量只在当前cpp有效所以链接它也不会被别的目标文件链接就不会有重复定义的问题了。总之在头文件中定义变量和函数要特别主意可能会导致链接错误。当然也不是所有定义都不能放到头文件中比如刚才说的const常量static全局变量就是例外还有内联函数可以定义在.h文件中因为内联函数会被拷贝到每个目标文件中也不会参与链接的过程。还有模板类必须放在头文件中定义这个下面会讨论这个。关于模板静态成员变量模板类模板函数必须声明和定义在头文件中原因是什么举个例子假设MyClass是模板类MyClass.hMyClass.cppmain.cpp编译的时候没有问题但是链接时会报错main.cpp找不到MyClass::Fun()如下图MyClass虽然定义了Fun函数但是MyClass.o中存在MyClass::Fun()而根据MyClass.h文件main.o中需要找到MyClass::Fun()的定义结果链接器哪都找不到只好报错了。(实际上通过objdump查看MyClass.o编译器都没有生成MyClass::Fun()因为编译器认为这个函数没人使用就直接优化掉了)如果非得在cpp中定义模板类的成员函数呢有一种方法就是要显示的在cpp文件中声明比如MyClass.cpp加上下面这行就不会有问题了但是缺点就是开发MyClass的程序员无从知道其他类是怎么使用这个模板的不可能把所有可能的模板参数全都一一的列在这里。所以模板类的定义还是要写在.h文件中那么如果main.cpp使用到了MyClass, 另外一个cpp也使用到了MyClass会不会产生重复代码导致重复定义呢不会编译器会处理好模板类的。下面是静态成员变量为什么静态成员变量的定义要放在cpp里(模板类的静态成员变量除外)静态成员变量和静态全局成员变量不同。静态成员变量的作用域可以是整个工程而静态全局变量的作用域只是当前的cpp。所以静态成员变量定义在.h中就会发生重定义错误。想要在程序员生涯内有更高的成就的话C/C就是一个既可以强化思维能力又可以打好编程基础的编程语言你想要做软件开发成为核心程序员的话学习C/C的话笔者有一个C/C的编程俩千人羣(Q艘索C/C编程学习13群)你如果感觉自学C/C语言有困难的话有兴趣学习或者了解一下C/C编程的小伙伴就可以进来交流。