從軟體誕生的那天開始,如何有效地重複利用代碼就成為了軟體的開發的需要,否則,每個程式都要從頭開始,程式設計就談不上樂趣,就無法大規模推廣了。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 //靜态庫的釋出,就是将其拷貝至相應的目錄;
四、動态庫的五步驟制作:
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", n);
return;
}
/* two simple cases: 4 and 6 */
if ((4 == n) || (6 == n)) {
printf("%i = %i + %i\n", 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", 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("\nis_prime\n");
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\n", i);
}
}
printf("%i primes in range of 1 to a thousand.\n", count);
/* prime_factors */
printf("\nprime_factors\n");
printf("prime factors of 12: ");
prime_factors(12);
printf("\n");
printf("prime factors of 13: ");
prime_factors(13);
printf("\n");
printf("prime factors of 876,512,779: ");
prime_factors(876512779);
printf("\n");
/* are_coprimes */
printf("\nare_coprime\n");
printf("Are %i and %i coprime? %s\n",
21, 22, are_coprimes(21, 22) ? "yes" : "no");
printf("Are %i and %i coprime? %s\n",
21, 24, are_coprimes(21, 24) ? "yes" : "no");
/* goldbach */
printf("\ngoldbach\n");
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)
人就像是被蒙着眼推磨的驢子,生活就像一條鞭子;當鞭子抽到你背上時,你就隻能一直往前走,雖然連你也不知道要走到什麼時候為止,便一直這麼堅持着。