Softwarové knihovny představují dlouhodobý, snadný a rozumný způsob opětovného použití kódu. Tento článek vysvětluje, jak vytvořit knihovny od začátku a zpřístupnit je klientům. Ačkoli se tyto dvě vzorové knihovny zaměřují na Linux, kroky pro vytváření, publikování a používání těchto knihoven platí i pro ostatní systémy podobné Unixu.
Ukázkové knihovny jsou napsány v C, což se pro daný úkol dobře hodí. Linuxové jádro je napsáno většinou v C a zbytek v assembleru. (Totéž platí pro sestřenice Windows a Linux, jako je macOS.) Standardní systémové knihovny pro vstup/výstup, sítě, zpracování řetězců, matematiku, zabezpečení, kódování dat atd. jsou rovněž napsány převážně v C. Chcete-li napsat knihovnu v C má tedy psát v rodném jazyce Linuxu. Navíc C nastavuje značku výkonu mezi jazyky na vysoké úrovni.
Další zdroje pro Linux
- Cheat pro příkazy Linuxu
- Cheat sheet pro pokročilé příkazy systému Linux
- Bezplatný online kurz:Technický přehled RHEL
- Síťový cheat pro Linux
- Cheat sheet SELinux
- Cheat pro běžné příkazy pro Linux
- Co jsou kontejnery systému Linux?
- Naše nejnovější články o Linuxu
Existují také dva vzoroví klienti (jeden v C, druhý v Pythonu) pro přístup ke knihovnám. Není žádným překvapením, že klient C má přístup ke knihovně napsané v C, ale klient Pythonu ukazuje, že knihovna napsaná v C může sloužit klientům z jiných jazyků.
Statické versus dynamické knihovny
Systémy Linux mají dva typy knihoven:
- statická knihovna (neboli archiv knihovny) je zapečen do staticky zkompilovaného klienta (např. jednoho v C nebo Rust) během fáze propojení procesu kompilace. Ve skutečnosti každý klient dostane svou vlastní kopii knihovny. Významná nevýhoda statické knihovny vystupuje do popředí, pokud je třeba knihovnu revidovat (například kvůli opravě chyby), protože každý klient knihovny musí být znovu propojen se statickou knihovnou. Dynamická knihovna, popsaná dále, se tomuto nedostatku vyhýbá.
- dynamická (neboli sdílená) knihovna je označena příznakem během fáze propojení staticky zkompilovaného klientského programu, ale klientský program a kód knihovny zůstávají jinak nepropojeny až do běhu – kód knihovny není zapečen do klienta. Za běhu dynamický zavaděč systému propojí sdílenou knihovnu s vykonávajícím klientem bez ohledu na to, zda klient pochází ze staticky kompilovaného jazyka, jako je C, nebo z dynamicky kompilovaného jazyka, jako je Python. Výsledkem je, že dynamickou knihovnu lze aktualizovat bez obtěžování klientů. A konečně, více klientů může sdílet jednu kopii dynamické knihovny.
Obecně platí, že dynamické knihovny jsou upřednostňovány před statickými, i když jsou náklady na složitost a výkon. Zde je návod, jak je každý typ knihovny vytvořen a publikován:
- Zdrojový kód knihovny je zkompilován do jednoho nebo více objektových modulů, což jsou binární soubory, které lze zahrnout do knihovny a propojit se spustitelnými klienty.
- Objektové moduly jsou zabaleny do jednoho souboru. Pro statickou knihovnu je standardní přípona
.a
pro "archiv." Pro dynamickou knihovnu je přípona.so
pro "sdílený objekt." Dvě vzorové knihovny, které mají stejnou funkcionalitu, jsou publikovány jako souborylibprimes.a
(statický) alibshprimes.so
(dynamický). Předponalib
se používá pro oba typy knihoven. - Soubor knihovny je zkopírován do standardního adresáře, takže klientské programy mohou bez problémů přistupovat ke knihovně. Typické umístění knihovny, ať už statické nebo dynamické, je
/usr/lib
nebo/usr/local/lib
; jiná umístění jsou možná.
Podrobné kroky pro budování a publikování jednotlivých typů knihoven budou brzy k dispozici. Nejprve však představím funkce C v těchto dvou knihovnách.
Funkce ukázkové knihovny
Dvě ukázkové knihovny jsou sestaveny ze stejných pěti funkcí C, z nichž čtyři jsou přístupné klientským programům. Pátá funkce, která je utilitou pro jednu z dalších čtyř, ukazuje, jak C podporuje skrývání informací. Zdrojový kód pro každou funkci je dostatečně krátký na to, aby funkce mohly být umístěny v jediném zdrojovém souboru, ačkoli více zdrojových souborů (např. jeden pro každou ze čtyř publikovaných funkcí) je možností.
Knihovní funkce jsou elementární a zabývají se různými způsoby s prvočísly. Všechny funkce očekávají jako argumenty celočíselné hodnoty bez znaménka (tj. nezáporné):
is_prime
funkce testuje, zda je její jediný argument prvočíslo.are_coprimes
funkce zkontroluje, zda její dva argumenty mají největšího společného dělitele (gcd) 1, který definuje co-primes.prime_factors
funkce uvádí hlavní faktory svého argumentu.goldbach
funkce očekává sudou celočíselnou hodnotu 4 nebo více, přičemž u tohoto argumentu uvádí kterýkoli součet dvou prvočísel; sčítacích dvojic může být více. Funkce je pojmenována po matematikovi z 18. století Christianu Goldbachovi, jehož domněnka, že každé sudé celé číslo větší než dvě je součtem dvou prvočísel, zůstává jedním z nejstarších nevyřešených problémů v teorii čísel.
Obslužná funkce gcd
je umístěn v nasazených souborech knihovny, ale tato funkce není přístupná mimo soubor, který obsahuje; klient knihovny tedy nemůže přímo vyvolat gcd
funkce. Bližší pohled na C funkce objasňuje pointu.
Více o funkcích C
Každá funkce v C má třídu úložiště, která určuje rozsah funkce. Pro funkce jsou dvě možnosti:
- Výchozí třída úložiště pro funkce je
extern
, což dává funkci globální rozsah. Klientský program může volat jakýkoliextern
funkce ve vzorových knihovnách. Zde je definice funkceare_coprimes
s explicitnímextern
:extern unsigned are_coprimes(unsigned n1, unsigned n2) {
...
} - Třída úložiště
static
omezuje rozsah funkce na soubor, ve kterém je funkce definována. V ukázkových knihovnách obslužná funkcegcd
jestatic
:static unsigned gcd(unsigned n1, unsigned n2) {
...
}
Funguje pouze v rámci primes.c
soubor může vyvolat gcd
a pouze funkce are_coprimes
tak činí. Když jsou statické a dynamické knihovny sestaveny a publikovány, ostatní programy mohou volat extern
funkce jako are_coprimes
ale ne static
funkce gcd
. static
storage class tak skrývá gcd
funkce z klientů knihovny omezením rozsahu funkce na jiné funkce knihovny.
Funkce jiné než gcd
v primes.c
soubor nemusí specifikovat třídu úložiště, která by měla výchozí hodnotu extern
. V knihovnách je však běžné vytvářet extern
explicitní.
C rozlišuje mezi definicemi funkcí a deklaracemi, což je důležité pro knihovny. Začněme definicemi. C má pouze pojmenované funkce a každá funkce je definována pomocí:
- Jedinečné jméno. Žádné dvě funkce v programu nemohou mít stejný název.
- Seznam argumentů, který může být prázdný. Argumenty jsou napsány.
- Buď typ návratové hodnoty (např.
int
pro 32bitové celé číslo se znaménkem) nebovoid
pokud není vrácena žádná hodnota. - Tělo uzavřené ve složených závorkách. Ve vykonstruovaném příkladu může být tělo prázdné.
Každá funkce v programu musí být definována přesně jednou.
Zde je úplná definice funkce knihovny are_coprimes
:
extern unsigned are_coprimes(unsigned n1, unsigned n2) { /* definition */
return 1 == gcd(n1, n2); /* greatest common divisor of 1? */
}
Funkce vrací booleovskou hodnotu (buď 0 pro nepravdu nebo 1 pro true), v závislosti na tom, zda mají dva celočíselné argumenty největší společný dělitel 1. Užitečná funkce gcd
vypočítá největší společný dělitel celočíselných argumentů n1
a n2
.
Deklarace funkce na rozdíl od definice nemá tělo:
extern unsigned are_coprimes(unsigned n1, unsigned n2); /* declaration */
Deklarace končí středníkem za seznamem argumentů; tělo neobklopují žádné složené závorky. Funkce může být v rámci programu deklarována vícekrát.
Proč jsou vůbec deklarace potřeba? V C musí být volaná funkce viditelná pro její volající. Existují různé způsoby, jak zajistit takovou viditelnost, v závislosti na tom, jak náročný je kompilátor. Jeden jistý způsob je definovat volanou funkci nad jejím volajícím, když jsou obě ve stejném souboru:
void f() {...} /* f is defined before being called */
void g() { f(); } /* ok */
Definice funkce f
lze přesunout pod volání z funkce g
if f
byly deklarovány nad výzvou:
void f(); /* declaration makes f visible to caller */
void g() { f(); } /* ok */
void f() {...} /* easier to put this above the call from g */
Ale co když volaná funkce sídlí v jiném souboru než její volající? Jak se funkce definované v jednom souboru zviditelní v jiném souboru, když každá funkce musí být v programu definována právě jednou?
Tento problém má dopad na knihovny, ať už statické nebo dynamické. Například funkce ve dvou primárních knihovnách jsou definovány ve zdrojovém souboru primes.c
, jejichž binární kopie jsou v každé knihovně; ale tyto definované funkce musí být viditelné pro klienta knihovny v C, což je samostatný program s vlastními zdrojovými soubory.
Poskytování viditelnosti mezi soubory je to, co mohou dělat deklarace funkcí. Pro příklady "primes" existuje hlavičkový soubor s názvem primes.h
který deklaruje, že čtyři funkce budou viditelné pro klienty knihovny v C:
/** 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);
Tyto deklarace slouží jako rozhraní určením syntaxe vyvolání pro každou funkci.
Pro pohodlí klienta textový soubor primes.h
by mohly být uloženy v adresáři na vyhledávací cestě kompilátoru C. Typická umístění jsou /usr/include
a /usr/local/include
. Klient C by #include
tento soubor záhlaví v horní části zdrojového kódu klienta. (Soubor hlavičky je tak importován do "hlavy" jiného zdrojového souboru.) Soubory hlavičky C také slouží jako vstup pro nástroje (např. Rust's bindgen
), které umožňují klientům v jiných jazycích přístup ke knihovně C.
Stručně řečeno, knihovní funkce je definována přesně jednou, ale deklarována všude tam, kde je potřeba; jakýkoli klient knihovny v C potřebuje deklaraci. Soubor hlavičky by měl obsahovat deklarace funkcí – nikoli však definice funkcí. Pokud hlavičkový soubor obsahoval definice, mohl být soubor zahrnut v programu C vícekrát, čímž se porušuje pravidlo, že funkce musí být v programu C definována přesně jednou.
Zdrojový kód knihovny
Níže je uveden zdrojový kód pro dvě knihovny. Tento kód, soubor záhlaví a dva ukázkové klienty jsou k dispozici na mém webu.
Funkce knihovny
#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 break */
}
}
}
Tyto funkce slouží jako drť pro knihovní mlýn. Tyto dvě knihovny jsou odvozeny z přesně stejného zdrojového kódu a hlavičkového souboru primes.h
je rozhraní C pro obě knihovny.
Vytváření knihoven
Kroky pro vytváření a publikování statických a dynamických knihoven se v několika detailech liší. Pro statickou knihovnu jsou vyžadovány pouze tři kroky a pro dynamickou knihovnu pouze dva další. Další kroky při budování dynamické knihovny odrážejí přidanou flexibilitu dynamického přístupu. Začněme statickou knihovnou.
Zdrojový soubor knihovny primes.c
je zkompilován do objektového modulu. Zde je příkaz se znakem procenta jako systémovou výzvou (moje komentáře představují dvojité ostré znaky):
% gcc -c primes.c ## step 1 static
Tím vznikne binární soubor primes.o
, modul objektu. Příznak -c
znamená pouze kompilovat.
Dalším krokem je archivace objektového modulu (modulů) pomocí linuxového ar
nástroj:
% ar -cvq libprimes.a primes.o ## step 2 static
Tři příznaky -cvq
jsou zkratky pro „create“, „verbose“ a „quick append“ (v případě, že je třeba do archivu přidat nové soubory). Připomeňme, že předpona lib
je standardní, ale název knihovny je libovolný. Název souboru knihovny musí být samozřejmě jedinečný, aby nedocházelo ke konfliktům.
Archiv je připraven k publikování:
% sudo cp libprimes.a /usr/local/lib ## step 3 static
Statická knihovna je nyní přístupná klientům, jejichž příklady se chystají. (sudo
je součástí, aby byla zajištěna správná přístupová práva pro kopírování souboru do /usr/local/lib
.)
Dynamická knihovna také vyžaduje jeden nebo více objektových modulů pro balení:
% gcc primes.c -c -fpic ## step 1 dynamic
Přidaný příznak -fpic
nařídí kompilátoru, aby vygeneroval na pozici nezávislý kód, což je binární modul, který se nemusí načítat do pevné paměti. Taková flexibilita je kritická v systému více dynamických knihoven. Výsledný objektový modul je o něco větší než modul vygenerovaný pro statickou knihovnu.
Zde je příkaz k vytvoření souboru jediné knihovny z objektových modulů:
% gcc -shared -Wl,-soname,libshprimes.so -o libshprimes.so.1 primes.o ## step 2 dynamic
Příznak -shared
označuje, že knihovna je sdílená (dynamická), nikoli statická. -Wl
flag představuje seznam možností kompilátoru, z nichž první nastavuje soname
dynamické knihovny , který je vyžadován. soname
nejprve určuje logické jméno knihovny (libshprimes.so
) a poté za -o
flag, název fyzického souboru knihovny (libshprimes.so.1
). Cílem je zachovat konstantní logický název a zároveň umožnit změnu fyzického názvu souboru s novými verzemi. V tomto příkladu je 1 na konci názvu fyzického souboru libshprimes.so.1
představuje první verzi knihovny. Logické a fyzické názvy souborů mohou být stejné, ale nejlepším postupem je mít samostatné názvy. Klient přistupuje ke knihovně prostřednictvím svého logického názvu (v tomto případě libshprimes.so
), jak brzy upřesním.
Dalším krokem je zpřístupnění sdílené knihovny pro klienty jejím zkopírováním do příslušného adresáře; například znovu /usr/local/lib again:
% sudo cp libshprimes.so.1 /usr/local/lib ## step 3 dynamic
Nyní je mezi logickým názvem sdílené knihovny vytvořen symbolický odkaz (libshprimes.so
) a jeho úplný fyzický název souboru (/usr/local/lib/libshprimes.so.1
). Nejjednodušší je zadat příkaz pomocí /usr/local/lib
jako pracovní adresář:
% sudo ln --symbolic libshprimes.so.1 libshprimes.so ## step 4 dynamic
Logický název libshprimes.so
by se nemělo měnit, ale cíl symbolického odkazu (libshrimes.so.1
) lze podle potřeby aktualizovat pro nové implementace knihoven, které opravují chyby, zvyšují výkon a tak dále.
Posledním krokem (preventivním) je vyvolání ldconfig
utilita, která konfiguruje dynamický zavaděč systému. Tato konfigurace zajišťuje, že zavaděč najde nově publikovanou knihovnu:
% sudo ldconfig ## step 5 dynamic
Dynamická knihovna je nyní připravena pro klienty, včetně dvou ukázkových, které následují.
Klient knihovny C
Ukázkový klient C je tester programu, jehož zdrojový kód začíná dvěma #include
směrnice:
#include <stdio.h> /* standard input/output functions */
#include <primes.h> /* my library functions */
Šikmé závorky kolem názvů souborů označují, že tyto hlavičkové soubory je třeba nalézt na vyhledávací cestě kompilátoru (v případě primes.h
, adresář /usr/local/include
). Bez tohoto #include
, kompilátor by si stěžoval na chybějící deklarace funkcí jako is_prime
a prime_factors
, které vycházejí v obou knihovnách. Mimochodem, zdrojový kód testovacího programu se nemusí vůbec měnit, aby bylo možné otestovat každou ze dvou knihoven.
Naproti tomu zdrojový soubor pro knihovnu (primes.c
) se otevře s těmito #include
směrnice:
#include <stdio.h>
#include <math.h>
Soubor záhlaví math.h
je vyžadována, protože funkce knihovny prime_factors
volá matematickou funkci sqrt
ve standardní knihovně libm.so
.
Zde je pro informaci zdrojový kód testovacího programu:
Program pro testování
#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;
}
Při kompilaci tester.c
do spustitelného souboru, ošidnou částí je pořadí příznaků odkazů. Připomeňme, že dvě ukázkové knihovny začínají předponou lib
a každý má obvyklou příponu:.a
pro statickou knihovnu libprimes.a
a .so
pro dynamickou knihovnu libshprimes.so
. Ve specifikaci odkazů předpona lib
a prodloužení odpadne. Příznak odkazu začíná -l
(malé L) a příkaz kompilace může obsahovat mnoho příznaků odkazu. Zde je úplný příkaz pro kompilaci pro program tester s použitím dynamické knihovny jako příklad:
% gcc -o tester tester.c -lshprimes -lm
První příznak odkazu identifikuje knihovnu libshprimes.so
a druhý příznak odkazu označuje standardní matematickou knihovnu libm.so
.
Linker je líný, což znamená, že na pořadí příznaků odkazu záleží. Například obrácení pořadí specifikací odkazu generuje chybu při kompilaci:
% gcc -o tester tester.c -lm -lshprimes ## danger!
Příznak, který odkazuje na libm.so
je první, ale žádná funkce z této knihovny není explicitně vyvolána v programu testeru; proto linker neodkazuje na math.so
knihovna. Volání sqrt
funkce knihovny se vyskytuje pouze v prime_factors
funkce, která je nyní obsažena v libshprimes.so
knihovna. Výsledná chyba při kompilaci programu testeru je:
primes.c: undefined reference to 'sqrt'
V souladu s tím by pořadí příznaků odkazu mělo informovat linker, že sqrt
je potřeba funkce:
% gcc -o tester tester.c -lshprimes -lm ## -lshprimes 1st
Linker vyzvedne volání funkce knihovny sqrt
v libshprimes.so
a proto vytvoří příslušný odkaz na matematickou knihovnu libm.so
. Existuje složitější možnost propojení, která podporuje buď pořadí příznaků spojení; v tomto případě je však snadný způsob, jak vhodně uspořádat příznaky odkazů.
Zde je nějaký výstup z běhu testovacího klienta:
is_prime
Sample prime ending in 1: 101
Sample prime ending in 1: 401
...
168 primes in range of 1 to a thousand.
prime_factors
prime factors of 12: 2 2 3
prime factors of 13: 13
prime factors of 876,512,779: 211 4154089
are_coprime
Are 21 and 22 coprime? yes
Are 21 and 24 coprime? no
goldbach
Number must be > 2 and even: 11 is not.
4 = 2 + 2
6 = 3 + 3
...
32 = 3 + 29
32 = 13 + 19
...
100 = 3 + 97
100 = 11 + 89
...
Pro goldbach
i relativně malá sudá hodnota (např. 18) může mít více dvojic prvočísel, které se sčítají (v tomto případě 5+13 a 7+11). Takové vícenásobné prvočíslo patří mezi faktory, které komplikují pokus o důkaz Goldbachovy domněnky.
Dokončení s klientem Python
Python, na rozdíl od C, není staticky kompilovaný jazyk, což znamená, že ukázkový klient Pythonu musí přistupovat k dynamické spíše než ke statické verzi knihovny prvočísel. K tomu má Python různé moduly (standardní a moduly třetích stran), které podporují rozhraní cizích funkcí (FFI), které umožňuje programu napsanému v jednom jazyce vyvolávat funkce napsané v jiném. Python ctypes
je standardní a relativně jednoduché FFI, které umožňuje kódu Pythonu volat funkce C.
Každý FFI má problémy, protože jazyky rozhraní pravděpodobně nebudou mít přesně stejné datové typy. Například knihovna prvočísel používá typ C unsigned int
, který Python nemá; ctypes
FFI mapuje C unsigned int
do Pythonu int
. Ze čtyř extern
C funkce publikované v knihovně prvočísel, dvě se chovají lépe v Pythonu s explicitními ctypes
konfigurace.
C funkce prime_factors
a goldbach
mít void
místo návratového typu, ale ctypes
ve výchozím nastavení nahrazuje C void
pomocí Pythonu int
. Při volání z kódu Pythonu pak dvě funkce C vrátí náhodnou (tedy nesmyslnou) celočíselnou hodnotu ze zásobníku. Nicméně ctypes
lze nakonfigurovat tak, aby funkce vracely None
(Pythonův typ null). Zde je konfigurace pro prime_factors
funkce:
primes.prime_factors.restype = None
Podobný příkaz zpracovává goldbach
funkce.
Níže uvedená interaktivní relace (v Pythonu 3) ukazuje, že rozhraní mezi klientem Pythonu a knihovnou prvočísel je přímočaré:
>>> from ctypes import cdll
>>> primes = cdll.LoadLibrary("libshprimes.so") ## logical name
>>> primes.is_prime(13)
1
>>> primes.is_prime(12)
0
>>> primes.are_coprimes(8, 24)
0
>>> primes.are_coprimes(8, 25)
1
>>> primes.prime_factors.restype = None
>>> primes.goldbach.restype = None
>>> primes.prime_factors(72)
2 2 2 3 3
>>> primes.goldbach(32)
32 = 3 + 29
32 = 13 + 19
Funkce v knihovně prvočísel používají pouze jednoduchý datový typ unsigned int
. Pokud tato knihovna C používala komplikované typy, jako jsou struktury, a pokud byly ukazatele na struktury předány a vraceny z funkcí knihovny, pak by FFI byla výkonnější než ctypes
může být lepší pro hladké rozhraní mezi Pythonem a C. Nicméně ctypes
příklad ukazuje, že klient Pythonu může používat knihovnu napsanou v jazyce C. Ve skutečnosti je oblíbená knihovna NumPy pro vědecké výpočty napsána v jazyce C a poté vystavena ve vysokoúrovňovém rozhraní Python API.
Jednoduchá knihovna prvočísel a pokročilá knihovna NumPy podtrhují, že C zůstává lingua franca mezi programovacími jazyky. Téměř každý jazyk může mluvit s C – a prostřednictvím C s jakýmkoliv dalším jazykem, který mluví s C. Python snadno mluví s C a jako další příklad může Java dělat totéž, když se Project Panama stane alternativou k Java Native Interface (JNI ).