GNU/Linux >> Linux の 問題 >  >> Linux

CでのLinuxソフトウェアライブラリを理解するためのガイド

ソフトウェアライブラリは、コードを再利用するための長年の、簡単で、賢明な方法です。この記事では、ライブラリを最初から作成してクライアントが利用できるようにする方法について説明します。 2つのサンプルライブラリはLinuxを対象としていますが、これらのライブラリを作成、公開、および使用する手順は、他のUnixライクなシステムにも適用されます。

サンプルライブラリはCで記述されており、タスクに適しています。 Linuxカーネルは、ほとんどがCで記述されており、残りはアセンブリ言語で記述されています。 (同じことが、macOSなどのWindowsおよびLinuxのいとこにも当てはまります。)入出力、ネットワーキング、文字列処理、数学、セキュリティ、データエンコーディングなどの標準システムライブラリは、同様に主にCで記述されます。したがって、CはLinuxのネイティブ言語で記述します。さらに、Cは高級言語間のパフォーマンスの基準を設定します。

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事

ライブラリにアクセスするための2つのサンプルクライアント(1つはC、もう1つはPython)もあります。 CクライアントがCで記述されたライブラリにアクセスできるのは当然ですが、Pythonクライアントは、Cで記述されたライブラリが他の言語のクライアントにサービスを提供できることを示しています。

静的ライブラリと動的ライブラリ

Linuxシステムには2種類のライブラリがあります:

  • 静的ライブラリ(別名ライブラリアーカイブ) コンパイルプロセスのリンクフェーズ中に、静的にコンパイルされたクライアント(CまたはRustのクライアントなど)にベイクされます。実際には、各クライアントはライブラリの独自のコピーを取得します。各ライブラリクライアントを静的ライブラリに再リンクする必要があるため、ライブラリを修正する必要がある場合(たとえば、バグを修正するため)、静的ライブラリの重大な欠点が浮き彫りになります。次に説明するダイナミックライブラリは、この欠点を回避します。
  • 動的(別名共有)ライブラリ 静的にコンパイルされたクライアントプログラムのリンクフェーズ中にフラグが立てられますが、それ以外の場合、クライアントプログラムとライブラリコードは実行時まで接続されません。ライブラリコードはクライアントにベイクされません。実行時に、システムのダイナミックローダーは、クライアントがCなどの静的にコンパイルされた言語であるか、Pythonなどの動的にコンパイルされた言語であるかに関係なく、共有ライブラリを実行中のクライアントに接続します。その結果、クライアントに迷惑をかけることなくダイナミックライブラリを更新できます。最後に、複数のクライアントがダイナミックライブラリの単一のコピーを共有できます。

一般に、動的ライブラリは静的ライブラリよりも優先されますが、複雑さとパフォーマンスにはコストがかかります。各ライブラリタイプが作成および公開される方法は次のとおりです。

  1. ライブラリのソースコードは、1つ以上のオブジェクトモジュールにコンパイルされます。これらのオブジェクトモジュールは、ライブラリに含めて実行可能クライアントにリンクできるバイナリファイルです。
  2. オブジェクトモジュールは単一のファイルにパッケージ化されています。静的ライブラリの場合、標準の拡張子は .aです。 「アーカイブ」のために。ダイナミックライブラリの場合、拡張子は .soです。 「共有オブジェクト」の場合。同じ機能を持つ2つのサンプルライブラリは、ファイル libprimes.aとして公開されています。 (静的)および libshprimes.so (動的)。プレフィックスlib 両方のタイプのライブラリに使用されます。
  3. ライブラリファイルは標準ディレクトリにコピーされるため、クライアントプログラムは大騒ぎせずにライブラリにアクセスできます。ライブラリの一般的な場所は、静的か動的かに関係なく、 / usr / libです。 または/usr / local / lib ;他の場所も可能です。

各タイプのライブラリを構築および公開するための詳細な手順は、まもなく公開されます。ただし、最初に、2つのライブラリのC関数を紹介します。

サンプルライブラリ関数

2つのサンプルライブラリは、同じ5つのC関数から構築されており、そのうちの4つはクライアントプログラムからアクセスできます。他の4つのうちの1つのユーティリティである5番目の関数は、Cが情報の非表示をどのようにサポートするかを示しています。各関数のソースコードは十分に短いため、関数を1つのソースファイルに格納できますが、複数のソースファイル(たとえば、公開されている4つの関数ごとに1つ)はオプションです。

ライブラリ関数は基本的なものであり、さまざまな方法で素数を処理します。すべての関数は、引数として符号なし(つまり、非負)の整数値を期待します:

  • is_prime 関数は、その単一の引数が素数であるかどうかをテストします。
  • are_coprimes 関数は、その2つの引数の最大公約数(gcd)が1であるかどうかをチェックします。これは、コプライムを定義します。
  • prime_factors 関数は、その引数の素因数をリストします。
  • ゴールドバッハ 関数は、4以上の偶数の整数値を想定し、この引数に合計される2つの素数をリストします。複数の合計ペアが存在する場合があります。この関数の名前は、18世紀の数学者Christian Goldbachにちなんで名付けられました。彼の推測では、2より大きい整数はすべて、2つの素数の合計であり、数論で最も古い未解決の問題の1つです。

ユーティリティ関数gcd デプロイされたライブラリファイルに存在しますが、この関数は、含まれているファイルの外部からはアクセスできません。したがって、ライブラリクライアントは gcdを直接呼び出すことはできません。 働き。 C関数を詳しく見ると、要点が明確になります。

C関数の詳細

Cのすべての関数には、関数のスコープを決定するストレージクラスがあります。関数には2つのオプションがあります:

  • 関数のデフォルトのストレージクラスはexternです 、関数にグローバルスコープを与えます。クライアントプログラムは、任意の externを呼び出すことができます サンプルライブラリの関数。関数are_coprimesの定義は次のとおりです。 明示的なextern
    extern unsigned are_coprimes(unsigned n1, unsigned n2) {
      ...
    }
  • ストレージクラスstatic 関数のスコープを、関数が定義されているファイルに制限します。サンプルライブラリでは、ユーティリティ関数 gcd staticです :
    static unsigned gcd(unsigned n1, unsigned n2) {
      ...
    }

primes.c内でのみ機能します ファイルはgcdを呼び出すことができます 、および関数 are_coprimesのみ そうします。静的ライブラリと動的ライブラリが構築および公開されると、他のプログラムが externを呼び出すことができます。 are_coprimesなどの関数 ただし、 staticではありません 関数gcd static したがって、ストレージクラスは gcdを非表示にします 関数のスコープを他のライブラリ関数に制限することにより、ライブラリクライアントから関数を作成します。

gcd以外の機能 primes.c内 ファイルはストレージクラスを指定する必要はありません。デフォルトではexternになります。 。ただし、ライブラリでは externを作成するのが一般的です。 明示的。

Cは、関数の定義と宣言を区別します。これは、ライブラリにとって重要です。定義から始めましょう。 Cには名前付き関数のみがあり、すべての関数は次のように定義されています:

  • 一意の名前。プログラム内の2つの関数に同じ名前を付けることはできません。
  • 引数リスト。空の場合があります。引数が入力されます。
  • 戻り値のタイプ(例: int ) 32ビット符号付き整数の場合)または void 値が返されない場合。
  • 中括弧で囲まれた本体。不自然な例では、本体が空である可能性があります。

プログラム内のすべての関数は、1回だけ定義する必要があります。

ライブラリ関数are_coprimesの完全な定義は次のとおりです。 :

extern unsigned are_coprimes(unsigned n1, unsigned n2) { /* definition */
  return 1 == gcd(n1, n2); /* greatest common divisor of 1? */
}

この関数は、2つの整数引数の最大公約数が1であるかどうかに応じて、ブール値(falseの場合は0、trueの場合は1)を返します。ユーティリティ関数 gcd 整数引数の最大公約数n1を計算します およびn2

定義とは異なり、関数宣言には本文がありません:

extern unsigned are_coprimes(unsigned n1, unsigned n2); /* declaration */

宣言は、引数リストの後にセミコロンで終わります。体を囲む中括弧はありません。関数は、プログラム内で複数回宣言される場合があります。

なぜ宣言が必要なのですか? Cでは、呼び出された関数はその呼び出し元に表示される必要があります。コンパイラーの煩わしさに応じて、このような可視性を提供するさまざまな方法があります。確実な方法の1つは、両方が同じファイルに存在する場合に、呼び出し元の上に呼び出された関数を定義することです。

void f() {...}     /* f is defined before being called */
void g() { f(); }  /* ok */

関数fの定義 関数gからの呼び出しの下に移動できます fの場合 呼び出しの上で宣言されました:

void f();         /* declaration makes f visible to caller */
void g() { f(); } /* ok */
void f() {...}    /* easier to put this above the call from g */

しかし、呼び出された関数がその呼び出し元とは異なるファイルにある場合はどうなるでしょうか。各関数をプログラムで1回だけ定義する必要がある場合、あるファイルで定義された関数を別のファイルでどのように表示できますか?

この問題は、静的か動的かに関係なく、ライブラリに影響します。たとえば、2つの素数ライブラリの関数は、ソースファイル primes.cで定義されています。 、そのバイナリコピーは各ライブラリにあります。ただし、これらの定義された関数は、独自のソースファイルを持つ別個のプログラムであるCのライブラリクライアントに表示される必要があります。

ファイル全体の可視性を提供することは、関数宣言が実行できることです。 「primes」の例では、 primes.hという名前のヘッダーファイルがあります。 これは、Cのライブラリクライアントに表示される4つの関数を宣言します:

/** 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);

これらの宣言は、各関数の呼び出し構文を指定することにより、インターフェースとして機能します。

クライアントの便宜のために、テキストファイル primes.h Cコンパイラの検索パス上のディレクトリに保存できます。一般的な場所は/usr / includeです。 および/usr / local / include 。 Cクライアントは#include このヘッダーファイルは、クライアントのソースコードの先頭近くにあります。 (したがって、ヘッダーファイルは別のソースファイルの「ヘッド」にインポートされます。)Cヘッダーファイルは、ユーティリティ(Rustの bindgen など)への入力としても機能します。 )他の言語のクライアントがCライブラリにアクセスできるようにします。

要約すると、ライブラリ関数は1回だけ定義されますが、必要に応じて宣言されます。 Cのライブラリクライアントには宣言が必要です。ヘッダーファイルには関数宣言が含まれている必要がありますが、関数定義は含まれていません。ヘッダーファイルに定義が含まれている場合、そのファイルはCプログラムに複数回インクルードされる可能性があるため、Cプログラムで関数を1回だけ定義する必要があるという規則に違反します。

ライブラリのソースコード

以下は2つのライブラリのソースコードです。このコード、ヘッダーファイル、および2つのサンプルクライアントは、私のWebサイトで入手できます。

ライブラリ機能

#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 */
    }
  }
}

これらの機能は、ライブラリミルの要点として機能します。 2つのライブラリは、まったく同じソースコードと、ヘッダーファイル primes.hから派生しています。 は両方のライブラリのCインターフェイスです。

ライブラリの構築

静的ライブラリと動的ライブラリを構築および公開する手順は、いくつかの詳細が異なります。静的ライブラリには3つの手順のみが必要であり、動的ライブラリにはさらに2つの手順が必要です。ダイナミックライブラリを構築するための追加の手順は、ダイナミックアプローチの追加された柔軟性を反映しています。静的ライブラリから始めましょう。

ライブラリソースファイルprimes.c オブジェクトモジュールにコンパイルされます。これがコマンドで、パーセント記号がシステムプロンプトになっています(二重の鋭い記号が私のコメントを紹介しています):

% gcc -c primes.c ## step 1 static

これにより、バイナリファイル primes.oが生成されます 、オブジェクトモジュール。フラグ-c コンパイルのみを意味します。

次のステップは、Linux arを使用してオブジェクトモジュールをアーカイブすることです。 ユーティリティ:

% ar -cvq libprimes.a primes.o ## step 2 static

3つのフラグ-cvq 「create」、「verbose」、「quickappend」の略です(新しいファイルをアーカイブに追加する必要がある場合)。プレフィックスlibを思い出してください は標準ですが、ライブラリ名は任意です。もちろん、ライブラリのファイル名は、競合を避けるために一意である必要があります。

アーカイブを公開する準備ができました:

% sudo cp libprimes.a /usr/local/lib ## step 3 static

静的ライブラリはクライアントがアクセスできるようになりました。その例は近日公開されます。 ( sudo ファイルを/usr / local / libにコピーするための正しいアクセス権を確保するために含まれています 。)

ダイナミックライブラリには、パッケージ化のために1つ以上のオブジェクトモジュールも必要です。

% gcc primes.c -c -fpic ## step 1 dynamic

追加されたフラグ-fpic 位置に依存しないコードを生成するようにコンパイラーに指示します。これは、固定メモリー位置にロードする必要のないバイナリ・モジュールです。このような柔軟性は、複数のダイナミックライブラリのシステムで重要です。結果のオブジェクトモジュールは、静的ライブラリ用に生成されたものよりもわずかに大きくなります。

オブジェクトモジュールから単一のライブラリファイルを作成するコマンドは次のとおりです。

% gcc -shared -Wl,-soname,libshprimes.so -o libshprimes.so.1 primes.o ## step 2 dynamic

フラグ-shared ライブラリが静的ではなく共有(動的)であることを示します。 -Wl flagは、コンパイラオプションのリストを導入します。最初のオプションは、ダイナミックライブラリの sonameを設定します。 、必須です。 soname 最初にライブラリの論理名を指定します( libshprimes.so )次に、 -oの後に続きます フラグ、ラ​​イブラリの物理ファイル名( libshprimes.so.1 )。目的は、物理ファイル名を新しいバージョンで変更できるようにしながら、論理名を一定に保つことです。この例では、物理ファイル名の末尾にある1 libshprimes.so.1 ライブラリの最初のバージョンを表します。論理ファイル名と物理ファイル名は同じでもかまいませんが、ベストプラクティスは別々の名前にすることです。クライアントは、論理名(この場合は libshprimes.so )を介してライブラリにアクセスします )、後で明確にします。

次のステップは、共有ライブラリを適切なディレクトリにコピーして、クライアントが簡単にアクセスできるようにすることです。たとえば、 / usr / local / lib again:

% sudo cp libshprimes.so.1 /usr/local/lib ## step 3 dynamic

これで、共有ライブラリの論理名( libshprimes.so )の間にシンボリックリンクが設定されました。 )とその完全な物理ファイル名( /usr/local/lib/libshprimes.so.1 )。 / usr / local / libを使用してコマンドを実行するのが最も簡単です。 作業ディレクトリとして:

% sudo ln --symbolic libshprimes.so.1 libshprimes.so ## step 4 dynamic

論理名libshprimes.so 変更する必要はありませんが、シンボリックリンクのターゲット( libshrimes.so.1 )バグを修正したり、パフォーマンスを向上させたりする新しいライブラリの実装については、必要に応じて更新できます。

最後のステップ(予防措置)は、 ldconfigを呼び出すことです。 システムの動的ローダーを構成するユーティリティ。この構成により、ローダーは新しく公開されたライブラリを確実に見つけることができます。

% sudo ldconfig ## step 5 dynamic

これで、ダイナミックライブラリは、次の2つのサンプルライブラリを含め、クライアントで使用できるようになりました。

Cライブラリクライアント

サンプルCクライアントはプログラムテスターであり、そのソースコードは2つの #includeで始まります。 ディレクティブ:

#include <stdio.h>  /* standard input/output functions */
#include <primes.h> /* my library functions */

ファイル名を囲む山かっこは、これらのヘッダーファイルがコンパイラの検索パス( primes.h の場合)で見つかることを示します。 、ディレクトリ / usr / local / include )。この#includeがないと 、コンパイラは、 is_primeなどの関数の宣言が欠落していることについて文句を言います。 およびprime_factors 、両方のライブラリで公開されています。ちなみに、テスタープログラムのソースコードは、2つのライブラリのそれぞれをテストするためにまったく変更する必要はありません。

対照的に、ライブラリのソースファイル( primes.c )これらの #includeで開きます ディレクティブ:

#include <stdio.h>
#include <math.h>

ヘッダーファイルmath.h ライブラリ関数prime_factorsが必要なため、 数学関数sqrtを呼び出します 標準ライブラリlibm.so

参考までに、テスタープログラムのソースコードは次のとおりです。

テスタープログラム

#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;
}

tester.cのコンパイル時 実行可能ファイルの場合、注意が必要なのはリンクフラグの順序です。 2つのサンプルライブラリがプレフィックスlibで始まることを思い出してください。 、それぞれに通常の拡張子が付いています: .a 静的ライブラリlibprimes.aの場合 および.so ダイナミックライブラリlibshprimes.soの場合 。リンク仕様では、プレフィックス lib そして拡張機能は失われます。リンクフラグは-lで始まります (小文字のL)、およびコンパイルコマンドには多くのリンクフラグが含まれる場合があります。例としてダイナミックライブラリを使用した、テスタープログラムの完全なコンパイルコマンドは次のとおりです。

% gcc -o tester tester.c -lshprimes -lm

最初のリンクフラグは、ライブラリ libshprimes.soを識別します 2番目のリンクフラグは、標準の数学ライブラリ libm.soを識別します。 。

リンカはレイジーです。つまり、リンクフラグの順序が重要です。たとえば、リンク仕様の順序を逆にすると、コンパイル時エラーが発生します。

% gcc -o tester tester.c -lm -lshprimes ## danger!

libm.soにリンクするフラグ 最初に来ますが、このライブラリの関数はテスタープログラムで明示的に呼び出されません。したがって、リンカは math.soにリンクしません。 図書館。 sqrtの呼び出し ライブラリ関数は、 prime_factorsでのみ発生します 現在libshprimes.soに含まれている関数 図書館。テスタープログラムのコンパイルで発生するエラーは次のとおりです。

primes.c: undefined reference to 'sqrt'

したがって、リンクフラグの順序は、 sqrtであることをリンカに通知する必要があります。 機能が必要です:

% gcc -o tester tester.c -lshprimes -lm ## -lshprimes 1st

リンカは、ライブラリ関数 sqrtへの呼び出しを取得します libshprimes.soにあります ライブラリ、したがって、数学ライブラリ libm.soへの適切なリンクを実行します 。リンクフラグの順序をサポートする、より複雑なリンクオプションがあります。ただし、この場合、簡単な方法はリンクフラグを適切に配置することです。

テスタークライアントの実行からの出力は次のとおりです。

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
...

goldbachの場合 関数では、比較的小さい偶数値(18など)でも、合計する素数のペアが複数ある場合があります(この場合、5+13と7+11)。このような複数の素数のペアは、ゴールドバッハの予想の証明の試みを複雑にする要因の1つです。

Pythonクライアントでのまとめ

Pythonは、Cとは異なり、静的にコンパイルされた言語ではありません。つまり、サンプルのPythonクライアントは、静的バージョンではなく動的バージョンの素数ライブラリにアクセスする必要があります。そのために、Pythonには、ある言語で記述されたプログラムが別の言語で記述された関数を呼び出すことができる外部関数インターフェイス(FFI)をサポートするさまざまなモジュール(標準およびサードパーティ)があります。 Python ctypes は、PythonコードがC関数を呼び出すことを可能にする標準的で比較的単純なFFIです。

インターフェース言語がまったく同じデータ型を持つ可能性は低いため、FFIには課題があります。たとえば、素数ライブラリはCタイプの unsigned intを使用します 、Pythonにはありません。 ctypes FFIはCのunsignedintをマップします Python intに 。 4つのexternのうち 素数ライブラリで公開されているC関数。2つは明示的なctypesを使用してPythonでより適切に動作します。 構成。

C関数prime_factors およびgoldbach voidがあります 戻り型ではなく、 ctypes デフォルトでは、Cの voidを置き換えます Python intを使用 。 Pythonコードから呼び出されると、2つのC関数はスタックからランダムな(したがって意味のない)整数値を返します。ただし、 ctypes 関数がNoneを返すように構成できます (Pythonのnullタイプ)代わりに。 prime_factorsの構成は次のとおりです 機能:

primes.prime_factors.restype = None

同様のステートメントがgoldbachを処理します 機能。

以下のインタラクティブセッション(Python 3)は、Pythonクライアントと素数ライブラリ間のインターフェイスが単純であることを示しています。

>>> 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

素数ライブラリの関数は、単純なデータ型 unsigned intのみを使用します。 。このCライブラリが構造などの複雑な型を使用し、構造へのポインタがライブラリ関数との間で受け渡されたり返されたりした場合、FFIは ctypesよりも強力です。 PythonとCの間のスムーズなインターフェースには、より良いかもしれません。それでも、 ctypes 例は、PythonクライアントがCで記述されたライブラリを使用できることを示しています。実際、科学計算用の人気のあるNumPyライブラリはCで記述され、高レベルのPythonAPIで公開されています。

単純な素数ライブラリと高度なNumPyライブラリは、Cがプログラミング言語の共通語であり続けることを強調しています。ほとんどすべての言語がCと通信でき、Cを介して、Cと通信する他の言語と通信できます。PythonはCと簡単に通信できます。別の例として、ProjectPanamaがJavaNative Interface(JNI 。


Linux
  1. awkを学ぶための実用的なガイド

  2. Linuxでの起動時にsystemdを理解する

  3. Linux 3Dグラフィックライブラリ?

  1. Linux 共有ライブラリの紹介 (共有ライブラリの作成方法)

  2. C++ Linux 開発環境をセットアップするには、サードパーティ ライブラリをどこに配置すればよいですか?

  3. ソースからコンパイルする方法を学ぶ (Unix/Linux/OSX)

  1. LinuxにNcursesライブラリをインストールする方法

  2. Linuxデスクトップを理解していますか?

  3. RPM を使用した Linux ソフトウェア管理の初心者向けガイド