不简单的hello world之C标准库(第二部分)

库(Library)

1 库(Library)的定义

2 为什么需要库

3 库是如何生成

4 库里面有什么

5 库的分类

6 如何创建库

7 什么是标准库

8 标准库的优点


这是承接上一篇文章《不简单的hello world值C标准库第一部分》。我们继续该主题的内容。

4. 库里面有什么


我们在上一节当中介绍了库是如何生成的,那么库里面有什么呢,关于这个问题可能有的同学会问了,你不是说了吗,里面不就是包含了我们写的程序的二进制CPU可以读懂的形式吗,亲爱的同学们,在上一节中主要是来讲述库如何生成的,所以这样说是为了为了让大家更容易的理解上一节,真实的情况是库里面不仅仅是包含了二进制指令,仅仅是指令是不够的,还需要的一项是什么呢,有的同学可能已经猜到了,那就是数据,关于库里面有什么同样不是能在这一小节中能完整描述的,我会在后面的文章给大家详细讲解,库里面到底有什么。敬请期待。

5. 库的分类


和任何东西一样,库也是有分类的。不用担心,库的分类很简单,就只有两种,动态库(Dynamic Library)和静态链接库(Static library)。

在Windows世界中,动态链接库就是大名鼎鼎的.dll结尾的文件,静态库是以.lib结尾的文件。

在Linux世界中,动态链接库是以.so结尾的文件,而静态库是以.a结尾的文件。

比如在Linux中,你有一个用来进行数学计算的库math,那么生成的动态库的名字就是libmath.so, 而对应的静态库的名字叫做libmath.a。如下图所以:

静态库

如图所示,这里希望强调的一点就是,同样的一份代码,我们即可以使用链接器(Linker)生成动态链接库,也可以生成静态链接库,至于是如何生成的,这两种库实现上有什么差别,同样的我会在下一篇文章当中给大家详细讲解。

可能又有同学继续问了,为什么这么麻烦的有两种库呢,又是动态链接库又是静态链接库的,这是很重要的一个问题,同样不适合在这里简单的描述描述,和之前的做法一样,我会在接下来的文章当中给大家详细讲解,因为我想系统性的给大家讲解计算机基础性的内容,好多相关的内容还没有写完,因为还没有写完所以具体调到哪一个章节暂时还不能确定,所以还希望同学们辛苦一点,都写完后在有这样的情况就可以直接告诉同学们调到那一章节直接看就好了(这里留下的问题会在下一个主题链接器中给大家详解介绍)。

6. 如何创建库


如何创建库?这一节和“库是如何生成的”不一样吗,是的,的确不一样,因为我也想不出一个很能直接表达清楚的标题,所以在这里特此解释一下,在“库是如何生成的”这一节当中,我们主要是引出链接器(Linker)这一重量级嘉宾,讲述库是由链接器来生成的,主角是链接器(Linker), 而这一节的主角是各位读这篇文章的同学们,主要是来讲我们如何指挥链接器(Linker)来生成我们需要的库。

本来想在这里给大家详细讲解一下的,但是考虑到这篇文章的主要内容是将库的,而如何创建动态库静态库和链接器紧密相关,因为这一部分的内容同样也在下一篇文章当中给大家详细讲解。

7. 什么是标准库


在前几节当中我们详细讲解了,什么是库,库是如何生成的以及库的分类和创建等,现在让我们回到文章最开始的内容,讲解一下标准库,下面我用一个例子来给大家形象的描述一下库以及标准库。

互联网的诞生让我们真正的见识到了高手在民间,所以神医也往往在民间,假如你是古代的皇帝想造福一方百姓,所以你派人找遍散落在民间的神医写就的药方,收集到这些药方后整理汇总成了一本书叫做《神医那些事》,这本书拯救了无数人的生命,载入史册造福至今。

在这个例子当中,民间神医高手写就的方子就类似于我们平时使用的各种函数,比如printf,把各种这样的函数汇集起来就叫做库(library),就好比《神医那些事》这本书,这本书里记载了针对各种疾病的明方,而库中也就是有各种函数的实现,所以你现在应该明白了所谓的库是什么了吧,无非就是里面包含了你可能用到的各种函数而已,而这些函数如果我们自己实现那无论是健壮性还是可维护性等都不如高手写好的函数,所以我们只需用就可以了。

那什么又是标准库呢,还是用上面的例子,假如明见的神医高手们对同一种疾病的描述很不一样(类似函数描述),所以作为皇帝的你大手一挥,既然描述各不一样我们就定义一个标准吧,对于一种疾病都有一个官方的描述,大家都以此为标准,而《神医那些事》这本书就是依据你制定的标准来写的,所以就好比标准库了。

8. 标准库的优点


有了标准库,其中一个很大的优点就是程序的可移植性,同样的hellworld程序,你在linux平台上可以跑起来,而且不加修改也可以在vs上跑起来,windows和linux这两个操作系统的实现方式完全不一样,但是这个helloworld可以在两个平台上不加修改的运行,这里就应该归功于标准库。是标准库屏蔽了底层操作系统的细节。程序员只需要调用标准库里的函数,标准库保证这些函数无论是在哪个平台都可以运行,怎么样是不是有种熟悉的味道,聪明的读者应该想到运行Java的JVM,Java之所以能跨平台运行不是Java代码本身而是因为运行Java的JVM可以在多个平台上运行(这里应该有两张图,作为对比),至于类似于java这样的语言到底是如何被类JVM的解释器运行起来的,我会在后面的章节中给大家详细介绍,对这个问题感兴趣的同学不要错过哦(获取这篇文章,请关注我的公共账号"码农的荒岛求生")。

上面提到的这种方法这是计算机科学当中常用的一种解决问题的方法,那就是增加一层来屏蔽底层差异。这里引用David Wheeler的一句名言:

All problems in computer science can be solved by another level of indirection.

计算机科学当中的任何问题都可以通过增加一层抽象层来解决。

关于Java的一次编译到处运行如图所示:

之所以Java是跨平台的,是因为不同平台上的JVM(如上图所示的JVM for x86 for Windows, JVM for Linux等)对Java代码的解释执行是一致的(可能有的同学不明白到底什么是解释执行,不用着急,我会在后面的文章当中不但给大家讲解清楚什么是解释执行,而且会给大家讲清楚是一些程序比如Java是如何解释执行的,欢迎大家关注我的公共账号: 码农的荒岛求生),只要相应的平台上有JVM,你写的Java程序就可以不加修改在该平台上执行。你可以把标准库想象成这里的JVM,当然这个类比不太恰当,原因在于Java程序是被JVM解释执行的,而我们写的C程序是依赖于标准库中的函数,C程序和标准库的地位是一样的,而Java程序是JVM的输入。但是通过这个类比你应该能明白标准库所起到作用了。

我们在helloworld中使用的printf函数正是在标准库中实现的。

现在你应该明白printf在哪里实现的了吧。我们平时使用malloc,strcpy等等都是在标准库中实现的,你也许会问如果要分配内存我们一定要使用malloc吗,当然不是这样的,我们在前面也讲解了,标准库中的各种函数也是普通的代码,如果你觉得分配内存用malloc不够酷的话你完全可以实现自己的malloc函数,你也许又会问了,malloc是怎么实现的呢,神奇的malloc是如何给我们的代码分配内存的呢,不要着急,我会在后面的内容中给大家讲解。之所以举这个例子就是想强调一点,标准库中函数也是普普通通的c程序,大家不要觉得标准库中的函数有什么的特别之处,没有什么特别之处,如果你喜欢的话你完全可以自己来实现一套标准库中的函数,但是通常情况下我们不会自己来实现这些烦人的细节的,标准库帮我们处理的很好了,大部分情况下只需要用标准库中的就可以了,当然在一些要求比较高的情况下是需要实现自己的函数的,比如上面举例用的malloc函数,Google就觉得标准库中的malloc实现的不是很好,自己用起来不是很顺手,所以Google就自己实现了一套内存分配方法,这些会在后面给大家讲解。

OK,让我们总结一下,

通常情况下,我们的程序需要依赖标准库提供的函数来帮助我们完成任务,如图所示:

但是也希望同学们记住一点就是,标准库中的函数也是普普通通的c程序并没有什么神秘之处,你完全可以实现自己的标准库函数。

今天给大家讲解了冰山的一角,C标准库,你看明白了吗,我们在上一节中留下了一个问题,那就是我们没有告诉编译器头文件(比如stdio.h)在哪里,这个我们我们没有在这一节中回答,为了给同学们更多思考的问题,这里这里再给大家一个思考题,就是我们也没有告诉编译器的实现文件在哪里,编译器是如何找到的呢,我们讲解的标准库到底在哪里呢?这些会在下一篇文章,链接器,中给大家讲解。


本篇文章较长,如果你能坚持看到这里,还是挺值得高兴的,谢谢你的支持,同时希望大家关注我的公共账号:码农的荒岛求生,那里会有最近的系列文章,我会用最直观最形象的方式给大家讲解各种计算机知识,如果哪里没有看明白希望大家能在评论区中提出改进意见,我会持续进行修改,直到大家都能很容易的看明白为止,谢谢大家。

猜你喜欢

转载自blog.csdn.net/github_37382319/article/details/81637677