Chapter IV ---- C language library

System Services Section

  • Write a program to achieve the display function string of characters on the screen, the code started to show the character on the screen, the middle of all this what happened?
  • Additional knowledge: I / O devices
    • I / O device is divided into three parts: the device, the device controller, the device driver
      • Equipment: monitor, keyboard, mouse, hard disk, a printer, a microphone, ...
      • Device controller: graphics cards, sound cards, network cards, hard disk controller, ...
      • Device drivers: Each device has a corresponding device driver
    • To display a character on the screen 显示器, 显卡and 相应的设备驱动程序, three are indispensable
  • Code starts to execute the character display from the screen, the middle of all this what happened? Monitor, video card and its corresponding device drivers, which are displayed at what position of the entire process?
    • Program sends a service request to the operating system
    • Operating system to translate the service request to the device driver
    • Device driver according to the service request representations device controller
    • Device controller final control device to complete the requested service our
  • Displaying a character sounds simple, but the implementation process is quite complex, but, in the process of realization, and is directly related to the program only on the screen 操作系统. As long as the program sends a service request to the operating system can be, and the rest of the things the program does not matter, as if the operating system is shielded all the details of the hardware, we do not need to know any relevant information about the hardware, operating system behind and stuff we have nothing to do.
  • The operating system provides services output characters on the screen as a program, for us, just need to send service requests to the operating system in accordance with the method specified by the operating system, you can achieve this functionality. In addition, the operating system also provides other services that will be provided by the operating system for short 系统服务.

II system calls

  • How the program should request specific system services to the operating system?

    • We need 按照操作系统所规定的方法to request system services, different operating systems corresponding to different request methods, but the principle is the same.

    • Linux operating system as an example, to explore how to request system services in the Linux operating system:

      • C语言并不具备请求系统服务的能力, Need to be embedded in a C program compiled code to implement the systems and services requested.

      • int main(){
            char A[] = {"Hello\n"};
            __asm__(
            	"mov rax, 1 \n\t"
                "mov rdi, 1 \n\t"
                "syscall \n\t"
                :
                :"S"(A),"d"(6)
            );
            
            return 0;
        }
      • __asm__();Is a compilation of identification code, used to distinguish assembly code and C code, if you do not write follow this format, you can not judge achieve C code is compiled code or C code, the code will be resolved in accordance with the C language syntax, This will inevitably lead to fail to compile.

      • " \n\t": C language and ;the same effect for distinguishing between the codes, and code indicating mov rax, 1is a complete code.

      • "mov rax, 1 \n\t": Rax is the system service number stored in the register, the register value is 1 rax, rax register is required to provide the service system 1, i.e., write file, and serving equipment.

      • "mov rdi, 1 \n\t": Rdi register file and decide which device to write, set the value of rdi register is 1, which is required rdi register to write console.

      • "syscall \n\t": Service requests the system to the operating system, the operating system to provide the corresponding service system according to the requirements of the above two lines of code.

      • "S"(A): S represents rsi register for storing a character to be displayed (A) of the memory address

      • "d"(6): D represents rdx register for character ( "Hello \ n") to display the number of stored

      • :: Previous instruction registers and variables of the C language for data exchange to colon, and other instructions to show the difference between

  • to sum up:

    • The operating system provides many services for us (such as displaying characters in the service console), we referred to the services provided by the operating system as "a system service."
    • Operating system provides us 调用系统服务的“入口点”,即syscall, we can call this system service through the syscall entry point, entry point used to invoke the system service referred to as "call the system" is. (syscall system call is shorthand)
    • Acquisition system services through system calls, we need to use assembly code to achieve.
  • According to the above summary, we can draw the following conclusions:

    • C language does not have the ability to display characters on the screen, displays the character is a very complicated matter;
    • C language just shows the character of this behavior is triggered by, just in code through system calls triggered this behavior show character, and show the character of this behavior specific implementation, is jointly done by the operating system and its equipment behind a series of .
  • In addition, C language does not have the 通过系统调用获取系统服务的能力system service is available through the system call 汇编代码to achieve, strictly speaking, C language only as a carrier assembly code, can barely be triggered by behavior.

The third encapsulated into the system call function

void write(char * A){//参数类型为指向char类型的指针
    int B = 0;
    for(char * C = A; C ++ != '\0'; B++);
     __asm__(
    	"mov rax, 1 \n\t"
        "mov rdi, 1 \n\t"
        "syscall \n\t"
        :
        :"S"(A),"d"(B)
    );
    
}

int main(){
    write("123\n");
    write("456\n");
    write("789\n");
    
    return 0;
}
  • B records the number of characters in the string (4), the number of characters does not include the final null character.
  • "S"(A): S represents rsi register for storing a character to be displayed (A) of the memory address (the first address).
  • "d"(B): D represents rdx register for character (B) the number of banks to be displayed.
  • role for loop: B is recorded by the variable number of characters to be displayed.
    - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-bkqwmY3q-1579599880107) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 3.png)]
    - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-8JVBrcvo-1579599880108) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 3-2.png)]

Section IV program consisting of multiple source files, translations and links

  • fun.c

  • void write(char * A){//参数类型为指向char类型的指针
        int B = 0;
        for(char * C = A; C ++ != '\0'; B++);
         __asm__(
        	"mov rax, 1 \n\t"
            "mov rdi, 1 \n\t"
            "syscall \n\t"
            :
            :"S"(A),"d"(B)
        );
        
    }
  • main.c

  • void write(* char);
    int main(){
        write("123456789\n");
        return 0;
    }
  • At the beginning of main.c program adds a prototype program void write(* char);, so even if there is no body of the function at compile time it does not produce a syntax error.

  • What to do to make the program print out the string on the screen?

    • 1. Copy the program fun.c main.c program.
      - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-mZCDdY1M-1579599880109) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 4-1.png)]
    • Main.c program will be compiled and fun.c function simultaneously.
      - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-TBpV8cJP-1579599880110) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 4-2.png)]
  • 源文件(.c)By 编译(gcc)generating可执行文件(.out)

    • The compilation process is divided into two steps: to translate the source file, after translation to get a target file, then the target file is a link.
    • That is: 源文件(.c)----> 翻译(gcc -c) ----> 目标文件(.o) ----> 链接(gcc)---->可执行文件(.out)
      • Translation: Simple, is to check the syntax of the source code, the source code is translated into machine instructions (translated into intermediate file).
      • Link: two source files corresponding to the link destination file, an executable file.
  • At the command line, type:

    • gcc -c fun.c -masm=intelEnter generate a fun.ofile
    • gcc -c main.cEnter generate a main.ofile
    • gcc main.o fun.oEnter generate a a.outfile
    • gcc fun.o main.cEnter, still generates a a.outfile

Section V library

  • When a very important function, which generally will be a function of the package, a separate storage, and generate its corresponding target (intermediate) file to facilitate its call other programs.
  • Assuming that there are fun1.c, fun2.c, fun3.c, main.c four source, which has fun1.c source assembly code, main.c program were called fun1.c, fun2.c, fun3 .c:
    • gcc -c fun1.c fun2.c fun3.c -masm=intelEnter, generate three corresponding target (intermediate) filefun1.o、fun2.o、fun3.o
    • gcc -c main.c fun1.o fun2.o fun3.oEnter to generate an executable filea.out
  • 如果文件越来越多,对其进行逐个编译就变得异常麻烦,使用ar r libxxx.a fun1.0 fun2.o fun3.o命令,将fun1.0 fun2.o fun3.o三个文件都存储到libxxx.a文件中,在编译时就可以更加方便的进行gcc main.c libxxx.a回车,生成一个可执行文件a.out,其中,以.a结尾的文件称之为库文件,用来存储函数,故函数库由此诞生,库函数则为函数库中的函数。
  • 注意:
    • 在给库文件或者说函数库起名字的时候,以lib开头。
    • 使用ar r libxxx.a fun1.0 fun2.o fun3.o命令生成库文件,当生成的库文件名已存在时,该命令会将目标文件添加到已存在的库文件中,如果没有以命令中lib开头命名的库文件,则会自动创建一个库文件,并将目标文件添加到库文件中。
    • 若库文件中已经存在命令中的目标文件,新的目标文件就会将库文件中已有的目标文件(同名的目标文件)覆盖掉。

第六节 静态库、共享库

  • 函数库分为两种:静态库(.a)和共享库(.so)。
  • 静态库(.a)
    • 如何生成静态库?
      • arr r libxxx.a fun1.o fun2.o fun3.o
    • 源文件和静态库如何进行链接生成可执行程序?
      • gcc main.c libxxx.a
    • 源文件和静态库链接生成的可执行程序中,包含它所用到的函数的代码,程序体积相对较大。(注意:可执行程序中只载入了它需要的函数,而不是载入整个静态库中的函数)
  • 共享库(.so)
    • 如何生成共享库?
      • gcc -shared -o libxxx.so fun1.o fun2.o fun3.o
    • 源文件和共享库如何进行链接生成可执行程序?
      • gcc main.c libxxx.so
    • 源文件和共享链接生成的可执行程序中不包含它所用到的函数的代码,程序体积相对较小。可以简单的理解为包含了共享库的一个引用。
    • 当可执行程序需要调用函数时怎么办?
      • 程序启动以后,当执行到共享库中的函数时,程序会找到共享库所在的位置,然后将其所需要的函数从共享库加载到内存中。
    • 程序到哪里找到共享库?
      • export_LD_LIBRARY_PATH = ./
    • 为什么叫做共享库?
      • 假设,有5个程序用到了共享库中的函数A,并且这5个程序同时在运行,函数A只会被加载1次,这5个程序将共享被加载到内存中的同一个函数A。
      • 优点:体积小,不会造成内存浪费、更新/升级程序更加方便,只需要更新共享库即可,不需要改动程序本身。

第七节 头文件、预处理指令、文件包含指令

  • 当我们需要大量的,频繁的使用函数库时,在程序的开头声明函数原型就变成了一件非常麻烦的事情,那么该如何弥补这个缺陷,使编程更加轻松?
    • 第一步:可以把一个函数库中所有函数原型的声明集中到一起,保存为一个以.h结尾的文件,这个文件称之为头文件。
      • 打开编辑器,将函数的原型写进去,保存为.h即可。
    • 第二步:#include "xxx.h"
      • #是预处理指令的标识
      • 预处理指令有很多种,include是其中之一,文件中包含指令
      • 作用:将它自己替换为它所指定的文件中的内容。
    • 程序的编译分为三步:
      • 预处理 ----> 翻译 -----> 链接
        • 预处理:根据指令修改源文件
        • 函数库
        • 头文件和文件包含指令相互配合可以使得程序的编写更加轻松。

第八节 API

  • 操作系统给我们提供了很多服务,比如在控制台显示字符串的服务,我们把操作系统提供的这些服务称为系统服务,有了操作系统提供的服务以后,只需要向操作系统发送服务请求,即可实现很强的功能,再换句话说就是系统服务的存在,就是为了方便程序的开发。
    - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-vbgVEpvj-1579599880110) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 8-1.png)]
  • 如何向操作系统请求系统服务?
    • 操作系统提供了获取系统服务的入口点,程序可以通过入口点向操作系统请求服务(比如linux中的syscall),用来获取系统服务的入口点,称之为“系统调用”。毕竟程序必须要通过它才能调用系统服务。
      • 通过系统调用获取系统服务的这个动作,由于需要用汇编代码实现,所以非常的繁琐,故需要简化操作,让程序的开发更方便。
    • 我们可以将发送服务请求的汇编代码嵌入C程序中,并将其封装为函数。
      • 一个系统服务就对应着一个函数,当需要调用系统服务时,就不需要单独编写系统调用的代码,直接调用对应的函数即可。
    • 当程序中使用了大量的函数时,函数原型的声明也将成为一个编程负担。可以将这些函数封装到库文件里面,形成一个函数库,并创建一个和库文件相对应的头文件,用于存储函数的原型声明,有了库文件和头文件以后,就可以将程序中大量的函数原型的声明替换为一条文件包含指令。
    • 操作系统所提供的服务非常强大,程序会大量使用它们,为了方便,一般只会通过库函数来使用它们,而这些函数就像是程序通往操作系统的一个入口(接口)。
    • 编写应用程序就避免不了要通过库函数调用系统服务,所以我们也把库函数称为应用程序编程接口,即API
    • 并不是所有的库函数都是用来封装系统调用的,有些库函数封装了系统调用,用于调用系统服务,比如在控制台显示字符的函数;有些库函数则没有封装系统调用,比如计算字符串长度的函数,比较两个数大小的函数,这些函数使用C语言给我们提供的各种运算符和语句就可以实现,所以并不是所有的库函数都是用来封装系统调用的。

第九节 POSIX(Unix、Linux)

  • C语言的诞生是为了重写UNIX操作系统,UNIX操作系统又是C语言程序设计的重要平台,所以,为了在UNIX平台上使用C语言进行编程更加的方便,快捷,UNIX操作系统中的系统调用,必然会被封装为C函数,并进一步的被封装为C库,以方便程序的开发。
  • 随着UNIX操纵系统的不断发展,其版本就越来越多,版本之间的差异也就越来越大,比如,UNIX-A中有一个系统服务A,而UNIX-B中可能就没有这个服务。它们的系统服务存在差异,则其函数库也必然存在差异,而各个版本之间的差异,严重影响了程序的可移植性。
  • Here Insert Picture Description
    • 假设我们在UNIX-A上写了一个程序,程序中使用了一个库函数,这个库函数就调用了系统服务A,那么这个程序就只能在UNIX-A中运行,而无法在UNIX-B中运行(原因:UNIX-B里面压根就没有这个函数,也没有这个服务,所以程序也就不具备可移植性)。
  • 后来,IEEE协会制定了一个标准 – POSIX标准(可移植性操作系统接口)。
  • POSIX标准最初的目的是提升应用程序在各种UNIX操作系统之间的可移植性。POSIX定义了操作系统必须提供的系统服务和一个函数库(并以头文件的形式发布),也就是说,它把系统服务和函数库都统一了起来,简单来说就是把接口统一了起来。
  • POSIX含义解析(以头文件的形式发布是什么意思)
    • 只提供了头文件,并没有提供库文件,也就是只定义了函数的原型。只是规定了有多少个函数,函数的名字是什么,函数的参数是什么,函数的返回值是什么,函数实现了什么功能(函数具体是如何实现的并不进行深究,但是必须要有这个函数,要实现这个功能)。
    • 库函数是由谁来提供的?
      • 库函数是由编译器厂商来提供的,编译器厂商会根据编译器所运行平台的具体情况来实现POSIX所定义的函数,然后,编译器厂商会把库文件、头文件和编译器打包在一起,故而我们在下载编译器的时候,里面就包含了库文件和头文件。每一种编译器都会提供一些流行的函数库。
    • 正是由于上述原因,我们在UNIX操作系统上进行编程的时候,就可以使用POSIX所定义的函数,这样,程序就可以在UNIX操作系统之间进行移植。
    • POSIX只是定义了函数原型,并没有定义函数体,也没有统一函数的具体实现,这样会造成什么影响?
      • 没有任何影响。
    • LINUX操作系统也支持POSIX标准,所以,编写运行在UNIX或者LINUX平台上的程序时,可以使用POSIX所定义的函数。

第十节 POSIX标准库到底是由谁来提供的

  • POSIX标准是给操作系统制定的,规定了操作系统必须提供的系统调用和函数库,需要注意的是,函数库是通过头文件来规定的。
  • 都有哪些操作系统支持POSIX标准?
    • UNIX和LINUX都支持POSIX标准,所以,UNIX和LINUX都必须按照该标准的要求,提供相应的系统调用及其函数库,而所谓的提供函数库,指的就是提供库文件及其相应的头文件。
  • POSIX标准是给操作系统制定的,如果某个操作系统支持这个标准,这个操作系统就必须按照标准的要求来提供相应的服务。POSIX标准分别对系统调用和函数库进行了规定,必须按照要求来提供相应的系统调用和库文件。所以我们说UNIX和LINUX都按照标准的要求,提供了相应的系统调用及其函数库。
  • 操作系统提供的函数库(头文件、库文件)和编译器所提供的函数库(头文件、库文件)之间,有什么区别
    • 二者提供的函数库本身并没有任何区别;
    • 操作系统支持POSIX标准,所以必须提供头文件和库文件。而编译器提供或者不提供都是可以的,没有一个强制的要求,只不过大多数的编译器都会提供一些比较流行的函数库给用户使用。

第十一节 动态链接库(windows)

  • windows中的函数库
    - [Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-dl8cbNRR-1579599880111) (E: \ workspace \ TyporaProjects \ C notes \ C language \ images \ Chapter IV library \ 11-1.png)]
    • windows是微软公司的私人产品,和其他的操作系统一样,为了能够更方便的在windows上开发程序,微软公司把windows的系统调用封装成了函数,并进一步封装成了函数库提供给开发者使用,需要注意的是,windows中的函数库并不是以.a或者.so结尾的,而是以.dll结尾的,windows将其称为动态链接库(Dynamic Linkable Library),动态链接库的性质和LINUX中的共享库的性质是一致的,都是在程序运行时进行链接的,显而易见,开发基于LINUX操作系统的程序,使用POSIX标准库将是最好的选择,使用POSIX标准库更利于程序在LINUX操作系统之间进行移植;开发基于windows操作系统的程序,使用windows提供的动态链接库将是最好的选择,由于windows是微软公司私有的,只有一个系列,并没有其他的分支,所以在windows中并不存在程序移植的问题。

第十二节 C语言标准的发展脉络(编译器)

  • 1973年,C语言诞生,没有标准

  • 1978年,《C程序设计语言》出版,K&R C / 经典C

  • 1989年,ANSIC(C89),定义了语言本身,定义了函数库(C标准库)

  • 1990年,ISO C(C90),ISO C == ANSI C

  • 1999年,ISO C(C99)

  • 2011年,ISO C(C11)

  • UNIX/LINUX提供了POSIX标准库。

  • windows提供了动态链接库。

  • 其他操作系统提供了其他相应的函数库来供开发者使用。

  • 如果程序中使用了动态链接库,则只能运行在windows上,如果程序中使用了POSIX标准库,则只能运行在UNIX/LINUX上,如果程序使用了其他函数库,则只能运行在函数库所对应的操作系统上。从当前阶段来看,函数库与操作系统是相关联的,C语言不具备可移植性。

  • C89、C90、C99、C11等标准是为C语言制定的,C89、C90、C99、C11等标准定义的函数库称为C标准库,而POSIX标准是为操作系统制定的,POSIX标准定义的函数库称为POSIX标准库。POSIX标准库是由操作系统提供的,C标准库与操作系统无关,在实际应用中,C标准库是由编译器提供的。
    - [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IIT1a344-1579599880111)(E:\workspace\TyporaProjects\C笔记\C语言\images\第四章 函数库\12-1.png)]
    总结:

    • 不同点:POSIX标准库是由操作系统提供的,C标准库是由编译器提供的。
    • 相同点:函数库的定义都是通过头文件(.h)来实现的。
  • 如何通过C标准库来实现可移植性?

    • 基本上所有的编译器都支持C标准库,运行在windows上的编译器支持C标准库,运行在UNIX/LINUX上的编译器支持C标准库,运行在其他操作系统上的编译器也支持C标准库,所以,如果在程序中使用C标准库,将程序移植到任何操作系统上,都可以成功运行。
    • 简单来说,C语言的可移植性是通过编译器对C标准库的支持来实现的。
发布了11 篇原创文章 · 获赞 3 · 访问量 859

Guess you like

Origin blog.csdn.net/Insist0224/article/details/104064296