zoukankan      html  css  js  c++  java
  • 从C 语言用户角度理解 Linux 的库

      从软件诞生的那天开始,如何有效地重复利用代码就成为了软件的开发的需要,否则,每个程序都要从头开始,编程就谈不上乐趣,就无法大规模推广了。C语言中库无疑是解决代码重复利用的重要途径之一,是非常简单合理的复用代码的一种方式。其实,软件库技术:长期存在;简单合理; 代码复用。下面以 Linux 为例,创建、发布和使用这些库,这些步骤也可以应用于其它类 Unix 系统。这些示例库使用 C 语言编写,适合该任务。Linux 内核大部分由 C 语言和少量汇编语言编写(Windows 和 Linux 的表亲如 macOS 也是如此)。用于输入/输出、网络、字符串处理、数学、安全、数据编码等的标准系统库等主要由 C 语言编写。所以使用 C 语言编写库就是使用 Linux 的原生语言来编写。除此之外,C 语言的性能也非常突出的。主要包括库和测试client程序用 C 语言客户程序来访问 C 语言编写的库,实际也可以用于其他编程语言。

    一、静态库和动态库  

    linux中主要有静态库和动态库两种。其中

      静态库:链接时直接将库文件的内容编码进代码;每个用到库文件的client程序都拥有库文件的拷贝;如果库文件更新了须要再次更新链接;

      静态库:链接阶段只是做了标识;多个client用到的同一个动态库文件在内存中只有一份拷贝;库文件的更新须要系统加载器将共享库和client程序链接即可;动态库性能不如静态库高效;动态库的复杂性高;动态库的应用异常灵活;

      1、库的源码先被便衣成一个或多个目标模块(二进制文件,但不包含可执行信息),目标模块可以被包含到库中;也可以被链接到可执行的二进制文件中

      2、目标模块被打包成一个文件(静态库以.a动态库以.o)特殊后缀名,一般加上lib前缀

      3、库文件的目录:/usr/lib   /usr/local/lib  ./ 当前目录

    二、C语言的函数

      1、函数的存储类决定着函数的应用范围,其中extern(默认)表明函数是整个库有效的;而static表明函数的范围被限制到函数所在的文件中;  

       通过函数的存储类型的修饰符,完成函数应用范围的区分与特定函数的隐藏与隔离

      2、函数的定义和声明,C语言中只允许命名函数

      函数定义:1)、函数名称必须唯一

           2)、参数必须指明类型,参数列表可以为空,也就是无需传入参数

             3)、返回必须有具体类型,若明确无返回,需指定为void,只能返回一个值

             4)、函数主体包含若干程序语句,须要用{}包括,

      3、函数的声明,与函数定义唯一的不同就是函数主体部分用 ; 替换{}部分即可;函数可以被多次声明,但只能被定义一次

      4、函数的应用,

            1)、C语言中规定变量需先定义后使用,

            2)、被调用函数需对调用函数是可见的,

            3)、对一些暂时没有实现的被调用的函数,可以通过先声明,后定义的方式避免编程过程被打断、

            4)、也可以通过先定义被调用函数,再调用;

      5、库

            1)、C语言中功能相近的函数形成库,

            2)、库中的函数通过其头文件实现对调用的函数的隐藏和封装,

            3)、头文件是客户程序与库函数的接口,

            4)、动态库的优势会更加明显

    三、静态库的三步走制作:

      以源代码primes.c为例,目标文件和库文件均以常规方式命名。

      1、生成目标文件

      gcc -c  primes.c                 //只编译,生成目标文件primes.o

      2、ar  -cvq  libprimes.a  primesc.o        //ar是静态库压缩的命令;选项cvq是创建、详细和快速添加等;库名须以lib为前缀,静态库以.a为后缀名,库名必须是唯一的;

      3、sudo  cp  libprimes.a  /usr/local/lib       //静态库的发布,就是将其拷贝至相应的目录;

    四、动态库的五步骤制作:

      以源代码primes.c为例,目标文件和库文件均以常规方式命名。

      1、生成位置无关文件

      gcc  primes.c  -c  -fpic              //编译选项fpic,生成位置无关代码

      2、gcc  -shared  -W1, -soname,   libshprimes.so  -o  libshprimes.so.1  primes.o //gcc是动态库制作的命令;

                             //选项shared表明库是共享(动态)的,而非静态的;

                             //选项soname指定了库的逻辑名称;客户程序一般通过库的逻辑名称访问库文件

                               //选项o指定了库的物理文件名称;

      3、sudo  cp  libshprimes.so.1  /usr/local/lib     //动态库的发布,就是将其拷贝至相应的目录;

      4、sudo  ln --symbolic  libshprimes.so.1  libshprimes.so //链接库的物理名称和逻辑名称

      5、sudo  ldconfig                //使用ldconfig配置系统的动态加载器,此过程是为了确保系统的中的库加载器能够正确找到新发布的库

    五、实战

      1、primes.h

    /** header file primes.h: function declarations **/
    extern unsigned is_prime(unsigned);
    extern void prime_factors(unsigned);
    extern unsigned are_coprimes(unsigned, unsigned);
    extern void goldbach(unsigned);

      2、primes.c

    #include <stdio.h>
    #include <math.h>
    
    extern unsigned is_prime(unsigned n) { 
      if (n <= 3) return n > 1;                   /* 2 and 3 are prime */
      if (0 == (n % 2) || 0 == (n % 3)) return 0; /* multiples of 2 or 3 aren't */
    
      /* check that n is not a multiple of other values < n */
      unsigned i;
      for (i = 5; (i * i) <= n; i += 6)
        if (0 == (n % i) || 0 == (n % (i + 2))) return 0; /* not prime */
    
      return 1; /* a prime other than 2 or 3 */
    }
    
    extern void prime_factors(unsigned n) {
      /* list 2s in n's prime factorization */
      while (0 == (n % 2)) {  
        printf("%i ", 2);
        n /= 2;
      }
    
      /* 2s are done, the divisor is now odd */
      unsigned i;
      for (i = 3; i <= sqrt(n); i += 2) {
        while (0 == (n % i)) {
          printf("%i ", i);
          n /= i;
        }
      }
    
      /* one more prime factor? */
      if (n > 2) printf("%i", n);
    }
    
    /* utility function: greatest common divisor */
    static unsigned gcd(unsigned n1, unsigned n2) {
      while (n1 != 0) {
        unsigned n3 = n1;
        n1 = n2 % n1;
        n2 = n3;
      }
      return n2;
    }
    
    extern unsigned are_coprimes(unsigned n1, unsigned n2) {
      return 1 == gcd(n1, n2);
    }
    
    extern void goldbach(unsigned n) {
      /* input errors */
      if ((n <= 2) || ((n & 0x01) > 0)) {
        printf("Number must be > 2 and even: %i is not.
    ", n);
        return;
      }
    
      /* two simple cases: 4 and 6 */
      if ((4 == n) || (6 == n)) {
        printf("%i = %i + %i
    ", n, n / 2, n / 2);
        return;
      }
      
      /* for n >= 8: multiple possibilities for many */
      unsigned i;
      for (i = 3; i < (n / 2); i++) {
        if (is_prime(i) && is_prime(n - i)) {
          printf("%i = %i + %i
    ", n, i, n - i);
          /* if one pair is enough, replace this with a break */
        }
      }
    }

      3、测试文件,testPrimes.c

    #include <stdio.h>
    #include <primes.h>
    
    int main() {
      /* is_prime */
      printf("
    is_prime
    ");
      unsigned i, count = 0, n = 1000; 
      for (i = 1; i <= n; i++) {
        if (is_prime(i)) {
          count++;
          if (1 == (i % 100)) printf("Sample prime ending in 1: %i
    ", i);
        }
      }
      printf("%i primes in range of 1 to a thousand.
    ", count);
    
      /* prime_factors */
      printf("
    prime_factors
    ");
      printf("prime factors of 12: ");
      prime_factors(12);
      printf("
    ");
      
      printf("prime factors of 13: ");
      prime_factors(13);
      printf("
    ");
      
      printf("prime factors of 876,512,779: ");
      prime_factors(876512779);
      printf("
    ");
    
      /* are_coprimes */
      printf("
    are_coprime
    ");
      printf("Are %i and %i coprime? %s
    ",
         21, 22, are_coprimes(21, 22) ? "yes" : "no");
      printf("Are %i and %i coprime? %s
    ",
         21, 24, are_coprimes(21, 24) ? "yes" : "no");
    
      /* goldbach */
      printf("
    goldbach
    ");
      goldbach(11);    /* error */
      goldbach(4);     /* small one */
      goldbach(6);     /* another */
      for (i = 100; i <= 150; i += 2) goldbach(i); 
    
      return 0;
    }

    或者:

    from ctypes import cdll
    
    cdll.LoadLibrary("libshprimes.so") ## logical name
    primes.is_prime(13)
    primes.is_prime(12)
    
    primes.are_coprimes(8, 24)
    primes.are_coprimes(8, 25)
    
    primes.prime_factors.restype = None
    primes.goldbach.restype = None
    
    primes.prime_factors(72)
    primes.goldbach(32)

    后续修改

     http://www.linuxeden.com/a/85624

    http://www.linuxeden.com/a/85505

    http://www.linuxeden.com/a/84903

    https://dp2px.com/2020/02/09/soft-hard-work/

    https://www.bilibili.com/video/av88392907/

    https://www.bilibili.com/video/BV1CX4y137rg/?spm_id_from=333.788.recommend_more_video.0

    人就像是被蒙着眼推磨的驴子,生活就像一条鞭子;当鞭子抽到你背上时,你就只能一直往前走,虽然连你也不知道要走到什么时候为止,便一直这么坚持着。
  • 相关阅读:
    CSS3动画
    Grid布局
    JS向上取整、向下取整、四舍五入等
    JS DOM资料
    关于setInterval和setTimeout中的this指向问题
    JavaScript 高级技巧 Memoization
    请求接口的方式
    HTTP协议知识
    CSS样式重置
    Chrome 为什么使用多进程,不使用多线程
  • 原文地址:https://www.cnblogs.com/guochaoxxl/p/14859789.html
Copyright © 2011-2022 走看看