栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++学习之路(二):include ,编译和链接

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++学习之路(二):include ,编译和链接

文章目录

C++学习之路(二):include ,编译和链接

前言一. include二.编译三.链接

0x00.link0x01.多个函数link0x02.include 结束

C++学习之路(二):include ,编译和链接 前言

本文主要是学习C++的include,编译和链接,借助Visual Studio工具加深了对于include的理解。

一. include

include是我们编码中使用比较频繁的指令,它的作用其实是在预处理的时候,将我们编写的头文件内容直接拷贝到目标文件中。是不是感到很惊讶?
下面用代码来证明一下:

end.h

} // 对这里就一个花括号

math.cpp

int add(int a, int b) {
	return a + b;
#include "end.h" // 这里的}给替换成了#include "end.h"

main.cpp

#include

int add(int a, int b);

int main() {
	std::cout << add(2, 3) << std::endl;
	return 0;
}

运行后成功打印2和3的结果,并且输出来。

是不是感到很惊讶,为了更加的清除了解到底发生了什么,我们请Visual Studio来帮忙。
点击项目的属性:

在如下图选择"预处理到文件"中选择是,然后点击应用。(注意配置和平台的选择,需要和你运行的时候选择一样的,我直接选择所有配置)

再次编译math.cpp文件,在如下目录中找到math.i文件

math.i的内容如下:

#line 1 "D:\codework\vswork\Project2\Project2\math.cpp"
int add(int a, int b) {
	return a + b;
#line 1 "D:\codework\vswork\Project2\Project2\end.h"
}
#line 4 "D:\codework\vswork\Project2\Project2\math.cpp"

从这里可以很清楚的看到,是直接把end.h的内容拷贝过来的。同理,加上#include,其实是把iostream.h的内容全部拷贝过来。

二.编译

C++的编译其实是把每一个.cpp文件都编译成后缀名为.obj的二进制文件(Visual Studio下)。
.obj文件你可以在你项目的平台和配置下找到,我的是在x64Debug目录下(每个人都不一样)。虽然它是个二进制的文件,但是我们可以借助Visual Studio修改,输出汇编指令:

针对main.cpp源文件,会在我的x64Debug目录下找到main.asm文件,打开之后就是一堆的汇编指令文件。

三.链接 0x00.link

首先看两段代码:
log.cpp

#include

void log(const char* msg) {
	std::cout << msg << std::endl;
}

main.cpp

// 注意这里没有include
// log是函数声明,学习C语言的都知道,使用函数需要声明一下
void log(const char* msg);

int main() {
	log("hello world !");
	return 0;
}

看到上面的代码你一定会很惊讶,为什么没有include任何东西,main.cpp可以正常运行起来。在main.cpp代码中只是声明了log函数,那么IDE是如何找到的,这里就是用到了链接(link)。

可以做个测试来测试下:
我们将log.cpp中方法名改为"logr",再编译main.cpp,你会发现编译不会报错,那是因为此时还没有链接(link),如果我们再运行的时候,就会发生错误。

error LNK2019: 无法解析的外部符号 "void __cdecl log(char const *)" (?log@@YAXPEBD@Z),函数 main 中引用了该符号

注意error LNK,这里说明这个是一个链接错误。点击运行之后链接器会进行链接,这时候链接器找不到void log(const char* msg);函数就会报link错误。

0x01.多个函数link

再创建一个log0.cpp,代码如下:

// 函数签名和log.cpp签名一样
void log(const char* msg) {
}

原来的log.cpp

#include

void log(const char* msg) {
	std::cout << msg << std::endl;
}

运行之后报如下错误:

error LNK2005: "void __cdecl log(char const *)" (?log@@YAXPEBD@Z) 已经在 log.obj 中定义

这个也是个link错误,原因是将log函数重复定义导致的,链接器在链接的时候不知道链接哪个函数。对于这种情况你可以在其中一个函数前面加上static(后续会对static做一个学习总结),比如在log0.cpp函数前面加上static,不让链接器去链接。或者直接删除其中一个。

0x02.include

对于函数main.cpp的函数声明,可以写一个.h的头文件代替函数声明,这样的好处是使用log函数的时候,就不需要每次使用每次都要声明。

log.h

#ifndef __LOG_H__
#define __LOG_H__

void log(const char* msg);

#endif

main.cpp

#include "log.h"
// 原来的log函数声明不需要了
int main() {
	log("hello world !");
	return 0;
}

事实上根据前面的include章节可以知道,这里的main.cpp等价于加函数声明的main.cpp。

结束

通过上面的总结,了解了:

    include预处理命令,是在编译之前就处理了,本质是直接将.h文件内容添加到目标文件中。编译是将源代码文件编译成一个个的.obj文件。运行的时候会将编译好的.obj文件进行链接(link)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779259.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号