我是一个从事开发10年的老程序员。最近花了点时间整理了一下C语言和C++的整合,一个完整的学习C语言和C++的路线和工具。如果你觉得自学C/C++编程很难,可以扫描下面的二维码。这是编程爱好者的聚集地。欢迎初学者和高级伙伴。希望你能通过自己的努力成为下一个优秀的程序员。
C/C++文件
C/C++程序文件包括. h.c.hpp.cpp,其中源文件(. c.cpp)是基本编译单元,头文件(. h.hpp)不会被编译器编译。
C/C++项目构建的过程分为以下几个步骤:预处理→编译→链接。
预编译
预编译的过程可以理解为编译器(实际上是一个预处理器,这里统称为编译器)在正式编译之前处理C/C++文件中的预处理命令,也就是以#开头的代码。
几种常用的预处理命令如下:
#包括……
#ifdef……#否则……#endif
#定义……
#杂注……
例如,下面是一个非常简单的类定义:
MyClass.h
MyClass.cpp
预编译后的样子:
您可以看到编译器已经替换了。文件中的#include位置。cpp文件和DEFAULT_VALUE定义的值在相应的位置。
编制
预编译后,编译器将编译每个源文件(。c .cpp)。如果编译成功,它将生成相应的目标文件,这是一个。o文件和一个。用于Windows的obj文件。
以Linux平台为例。上面的MyClass.cpp编译完成后,会生成MyClass.o文件。
使用objdump查看目标文件MyClass.o的内容
编译器会把MyClass::Fun()的名字改成_ZN7MyClass3FunEv,这个过程叫做Mangle。因为C++支持重载和覆盖等特性,所以编译器必须用唯一的标识符来表示函数。该字符串是编译器生成的唯一标识符。
这里我们要单独说一下头文件。既然头文件不是编译单元,那么它的作用是什么?
头文件负责“声明”。编译MyClass.cpp时,编译器必须先找到其对MyClass类和成员函数fun()的声明,才能正确编译该函数。
如果有其他CPP需要使用MyClass,他们也需要它的声明。例如
主页面
添加# include & # 34MyClass.h & # 34编译器在编译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没有对应的头文件,或者头文件缺少对应的声明。
然而,重复的声明通常#包含相同的头文件。比如B.h和C.h都包含A.h,然后main.h包含B.h和C.h,导致A.h两次包含在main中。
解决这个问题的方法是在第一行加上。h文件。
#pragmaonce
或者,使用#ifndef…#定义…#endif语句块。
-链接错误,常见的错误有两种,无定义和重复定义,类似于上面的无声明和重复声明。(这里的定义是指功能实现)
先讨论一下对xxx的未定义引用。
通常是因为声明并使用了函数,但没有定义。比如上面的MyClass.cpp,如果没有实现Fun(),编译时MyClass.cpp和main.cpp都不会报错,但是链接时会报错找不到Fun()。
当然,如果Fun()没有被main.cpp调用,即使没有实现,整个构造过程也不会出错,因为链接器根本不会去寻找这个函数的定义。
然后是多重定义。
两个目标文件中存在引用的相同定义,链接器在链接时不知道使用哪一个。这个问题通常是由头文件中定义的全局函数和全局变量引起的。导致多个目标文件包含相同的全局函数和全局变量定义。
解决方法是在头文件中声明,将定义放在cpp文件中,或者在定义中添加const或static等修饰符,这些带有const和修饰符的变量在链接时会被特殊处理。
Const只适合定义常量变量,static定义静态全局变量,只在当前cpp中有效,所以链接它不会被其他目标文件链接,所以不会有重复定义的问题。
简而言之,在头文件中定义变量和函数要特别考虑,这可能会导致链接错误。
当然,并不是所有的定义都不能放在头文件里。比如刚才提到的const常量,静态全局变量是个例外,内联函数可以在。h文件,因为内联函数将被复制到每个目标文件,不会参与链接过程。
还有一些模板类必须在头文件中定义,这将在下面讨论。
关于模板,静态成员变量
模板类模板函数必须在头文件中声明和定义。为什么?例如,假设MyClass是一个模板类。
MyClass.h
MyClass.cpp
主页面
编译的时候没有问题,但是链接的时候会报错。main.cpp找不到我的类
虽然MyClass定义了Fun函数,但是myclass
结果链接器哪里都找不到,只好报错。(实际上,编译器没有生成我的类
如果你必须在cpp中定义模板类的成员函数,一种方法是在cpp文件中声明它,比如
MyClass.cpp
添加以下几行,不会有问题,但缺点是开发MyClass的程序员没有办法知道其他类是如何使用这个模板的,也不可能在这里列出所有可能的模板参数。
因此,模板类的定义应该写在。h文件。
所以如果main.cpp使用我的类
以下是静态成员变量。为什么静态成员变量的定义要放在cpp中(模板类的静态成员变量除外)?
静态成员变量不同于静态全局成员变量。
静态成员变量的范围可以是整个项目,而静态全局变量的范围只是当前的cpp。因此,当静态成员变量在。h.
希望对大家有帮助!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。