百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

linux下的C开发8,三分钟弄懂静态链接和动态链接方式的区别

cac55 2024-10-31 12:21 15 浏览 0 评论

前面花了 7 节介绍如何搭建基本的 linux 下的 C语言开发环境,现在终于可以愉快的进行 C语言程序开发了。小编决定先介绍下 linux 下常用的一些库函数,一来可以熟悉 linux 中有哪些现成的轮子可用,二来可以锻炼一下我们的 C语言编程水平,毕竟这系列文章是面向 C语言初学者,而不是大牛的。

在 linux 下查看库函数的文档

linux 中有大量的库函数和系统函数可用,这么庞大的函数量,我们不可能全部记下来。而且,即使是一些常用的函数,有时也会记不清它需要包含什么头文件,它的参数类型是什么样的,以及它有哪些返回值。

这时,查看函数的说明文档就很必要了。本系列文章前面几节介绍安装的 ubuntu linux 环境,非常贴心的提供了 man 手册,所以如果我们想查看某个函数的说明文档,直接输入 man 命令查询即可,例如查询 printf 的文档,只需输入

# man 3 printf

就什么都有了,文档非常详细,包含了所需头文件,函数原型,功能描述,返回值等信息,有些函数甚至还会附有示例代码。

所以说 linux 对程序员非常友好,连函数文档都能一键查询。

动态链接库和静态链接库

使用我们按照之前几节配置好的 vim 输入以下代码:

// 文件名 t.c
#include <stdio.h>
int main()
{
 printf("hello embedTime\n");
 return 0;
}

这段代码包含了 stdio 头文件,调用了库函数 printf,所以编译它肯定会使用链接库。linux 系统有两种链接库,一种常常被称为“静态链接库(static library)”,还有一种常被称作“动态链接库(shared library)”。

动态链接是应用非常广泛的方式。动态链接库的英文字面意思可以翻译为“共享的库”,的确如此,使用动态链接库的程序在加载时,linux 内核会检查程序用到的库是否已经在内存中,如果在,则 linux 内核不再重新加载库,直接就执行程序了。所以,多个程序可以共享一个库,这实际上可以节约资源。

对于静态链接库来说,程序链接时会将其作为程序的一部分,因此最终生成的可执行程序相比于动态链接方式,会更大一点。

编译上面的程序:

# gcc t.c -o shared.out

这条编译语句使用的是动态链接方式。为 gcc 命令附加 -static 命令,可以以静态链接方式编译程序:

# gcc t.c -static -o static.out

现在我们查看一下这两种链接方式生成的可执行程序大小对比:

# ls -ahl
total 888K
drwxr-xr-x 3 root root 4.0K Dec 17 22:40 .
drwxr-xr-x 8 root root 4.0K Dec 11 10:28 ..
drwxr-xr-x 2 root root 4.0K Dec 17 22:39 his
-rwxr-xr-x 1 root root 8.4K Dec 17 22:40 shared.out
-rwxr-xr-x 1 root root 857K Dec 17 22:40 static.out
-rw-r--r-- 1 root root 76 Dec 17 21:37 t.c

很容易看出,使用静态链接方式生成的可执行程序,要比使用动态链接方式生成的可执行程序大 100 多倍。虽然几百 KB 对于大多数 linux 主机来说不算什么,但是嵌入式系统资源一般都非常紧缺,这时再轻易使用静态链接就非常奢侈了。

使用静态链接也是有好处的,生成的可执行程序能够脱离库独立运行,而使用动态链接的可执行程序则不能脱离库独立运行。

静态链接和动态链接的可执行程序,执行过程有哪些不同

上面讨论了 linux 中程序链接的两种方式,既然可执行程序体积相差这么多,那它们的执行过程也应该有所差异了?的确如此,现在我们一起来分析下。在linux中分析程序的执行过程,可以使用 strace 命令。

先分析 shared.out,我们输入 strace ./shared.out,会发现有一大堆输出信息:

# strace ./shared.out
execve("./shared.out", ["./shared.out"], [/* 22 vars */]) = 0
brk(0) = 0x1a66000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=33518, ...}) = 0
mmap(NULL, 33518, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe241ff2000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1857312, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe241ff1000
mmap(NULL, 3965632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe241a10000
mprotect(0x7fe241bce000, 2097152, PROT_NONE) = 0
mmap(0x7fe241dce000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1be000) = 0x7fe241dce000
mmap(0x7fe241dd4000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe241dd4000
close(3) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe241fef000
arch_prctl(ARCH_SET_FS, 0x7fe241fef740) = 0
mprotect(0x7fe241dce000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7fe241ffb000, 4096, PROT_READ) = 0
munmap(0x7fe241ff2000, 33518) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe241ffa000
write(1, "hello embedTime\n", 16hello embedTime
) = 16
exit_group(0) = ?
+++ exited with 0 +++

这些输出信息即为 linux 执行程序的过程。每一个函数,都可以通过 man 命令查询其手册。几个主要的过程如下:

就是加载库到内存,再执行程序,最后调用系统调用 exit 结束程序。

现在再来看看静态链接的程序 static.out,同样使用 strace 命令查看:

# strace static.out

可以看出,因为链接时,编译器直接把静态库作为程序的一部分了,所以这里相比于动态链接的程序,少了很多将库映射到内存的操作:

到这里,动态链接和静态链接程序执行时的不同点,就清楚了。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

相关推荐

14款健身APP蹿红 看看下载最多的是哪款?

Zombies,Run!($3.99,安卓,iOS)如果你的运动理念是:除非有人追,否则绝不跑起来,那么这款APP应该适合你。Zombies,Run!这款程序把单调的跑步过程变身为躲避僵尸的游戏...

微软官方彩蛋庆祝《回到未来》纪念日

2015年10月21日,是MartyMcFly和Brown博士回到未来的时间。现在,这一天真的到了,那么当时影片中展示的一些科技产品究竟有多少实现了呢?作为一家走在技术前沿的公司,日前,微软就在M...

时尚圈最潮同志情侣 帅到没朋友(同志情侣微信头像)

来源:MSN时尚综合|2015-03-0419:45:15男演员ZacharyQuinto(中)与男模MilesMcMillan(右)于纽约街头公开热吻。情人节这个拥有不同起源传说,最早可以...

IE浏览器阻止过期ActiveX控件或将影响网银的使用

IE浏览器网银IE浏览器网银如果经常使用IE浏览器浏览网页的用户,可能都有遇到过浏览器窗口提示安装ActiveX控件的情况,一般情况下用户也是会选择直接安装。ActiveX控件广义上是指微软公司的整...

如何使Microsoft Band连接到WP设备

如果你幸运地购买到了MicrosoftBand,那么恭喜你。现在我们(winbeta)推出了“帮助系列”,那些尚未买到MicrosoftBand的朋友可以了解设备的一些新功能,以及设备的其他关键特...

毕业生不得不看的五大骗局全揭秘(毕业生防骗)

目前,距离高校大学生毕业已不足100天,大部分毕业生都十分忙碌。论文定稿、答辩,参加招聘、面试等成了应届毕业生的头等大事。但随着毕业季的临近,不法分子专门针对毕业生的诈骗高发期也随之来临。360手机安...

菠萝觅生活是O2O应用流量入口最大的供应商

现在主流的传统O2O生活服务,他们其实都有一个共通点,那就是各行其道。打车有快的,滴滴,外卖有饿了么,买机票有去哪儿网…每个APP都有着自己的核心竞争力。而用户呢?既想拥有海量有趣应用,又担心占用过多...

WP8.1版MSN健康应用,现已支持锁屏计步

IT之家(www.ithome.com):WP8.1版MSN健康应用,现已支持锁屏计步@WP之家报道,微软今天已将必应系列应用品牌归为MSN,除此之外,WP8.1版MSN健康和天气应用也获得一些新的...

短信就能传播手机病毒?看完推理惊呆了!

很多人都收到过一种带网址的陌生短信,有的人会点击网址看看,有的还会在好奇心驱使下回复短信。近日《北京新发现》栏目报道了一起离奇的电信诈骗案,事主耿先生的银行卡从未离身,但是在收到一条带网址的陌生短信,...

微软OneClip:我承包了你的剪贴板(微软onedrive云空间)

不久前,Twitter用户WalkingCat曝光了微软一款名为OneClip的应用。这是一款剪贴板应用,根据描述这款应用将覆盖Windows10(包括桌面和移动)、iOS和Android平台,可以...

Windows 10手机应该是什么样?微博用户给出了概念图

随着Windows10发布的不断临近,WindowsPhone的用户对Windows10的旗舰手机的期望也越来越高,我们WP中文网也在微博上发出了同样的问题,搜集用户对Windows10的硬...

云管家出席武汉2015年支付宝O2O生态峰会

2月4日,蚂蚁金服O2O生态峰会在武汉启幕。此次峰会展现了2015年蚂蚁金服在O2O领域的开放思路和策略,以及合作伙伴对O2O的创新观念及思路分享,吸引了武汉近3000名企业大佬、众多创业者、第三方服...

微软将于下周开启Windows开发中心帐号迁移工作

自下周开始微软将启动Windows开发中心的帐号迁移工作。根据WindowsBuildingApps博客透露Windows开发中心帐号迁移工作将会分为几个阶段。首个阶段从下周开始持续到今年7月份...

如何解绑已经合并的MSN账户和Skype账户?

如果您绑定的账户已经充值,建议您把产品消耗完毕后,再进行解绑。当您需要解绑合并的账户时,可登入Skype点卡账户自助操作。输入Skype或MSN账号、密码登录账户:登录后,可在页面左下角选择语言"中文...

微博账号已显示所属MCN机构,成为目前第二个上线该功能的平台

7月25日,多位网友发现,部分微博大V的个人主页已经显示其所属的MCN机构名称,微博也成为目前第二个上线该功能的平台。【来源:中新经纬】声明:此文版权归原作者所有,若有来源错误或者侵犯您的合法权益,您...

取消回复欢迎 发表评论: