mmap 関数を使用して C でメモリに書き込む

Mehvish Ashiq 2023年10月12日
  1. C の mmap() 関数
  2. mmap() を使用して C でメモリに書き込む
mmap 関数を使用して C でメモリに書き込む

この記事では、mmap() 関数、それが取るパラメーターの数、および mmap() を使用して C プログラミングでメモリに書き込む方法を学びます。

C の mmap() 関数

この関数を使用して、プロセスのアドレス空間とデバイスまたはファイルのいずれかをマップします。 mmap() 関数は、メモリの n バイトの書き込み可能な匿名およびプライベート マッピングを要求します。

匿名マッピングとプライベート マッピングは、ファイルによってサポートされておらず、別のプロセスと共有されていないことを意味します。 mmap() を使用するには、ヘッダー ファイルをインクルードする必要があります。

#include <sys/mman.h>

次の 6つの引数を取ります。

void *mmap(void *address, size_t length, int protect, int flags, int filedes,
           off_t offset)

この関数の使用に入る前に、引数について説明しましょう。

  1. address - マッピングに使用する優先開始アドレスを提供します。 他にマッピングがない場合、カーネルは近くのページ境界を選択してマッピングを作成します。

    それ以外の場合、カーネルは新しいアドレスを選択します。 このパラメーターの値が NULL の場合、カーネルは適切と思われる場所にマッピングを配置します。

  2. 長さ - バイト数がマップされます。

  3. protect - 許可されるアクセスの種類を制御します。 たとえば、読み取りアクセスの場合は PROT_READ、書き込みアクセスの場合は PROT_WRITE、実行の場合は PROT_EXEC です。

  4. フラグ - マップの性質を制御するために使用されます。 一般的で便利なフラグの一部を以下に示します。

    • MAP_SHARED - マッピングを他のプロセスと共有します。
    • MAP_FIXED - システムは、address パラメータで指定された同じマッピング アドレスを使用することを強制されます。
    • MAP_ANONYMOUS / MAP_ANON - 匿名マッピングを作成します。
    • MAP_PRIVATE - このフラグを使用している間、マッピングは非公開になり、他のユーザーには表示されません。
  5. filedes - ファイル記述子はマップされるはずです。

  6. offset - ファイル マッピングはこのオフセットから開始します。

mmap() が正常に機能した場合は 0 を取得します。 それ以外の場合、MAP_FAILED が返されます。

mmap() を使用して C でメモリに書き込む

さまざまな例を練習して mmap() を理解しましょう。

コード例 (メモリ割り当て の場合):

#include <stdio.h>
#include <sys/mman.h>

int main() {
  int N = 5;
  int *ptr = mmap(NULL, N * sizeof(int), PROT_READ | PROT_WRITE,
                  MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);

  if (ptr == MAP_FAILED) {
    printf("Mapping Failed\n");
    return 1;
  }

  for (int i = 0; i < N; i++) ptr[i] = i * 10;

  for (int i = 0; i < N; i++) printf("[%d] ", ptr[i]);

  printf("\n");
  int err = munmap(ptr, 10 * sizeof(int));
  if (err != 0) {
    printf("Unmapping Failed\n");
    return 1;
  }

  return 0;
}

出力:

[0] [10] [20] [30] [40]

mmap() 関数を使用して、PROT_READ | を使用している場所にメモリを割り当てます。 PROT_WRITE マップされた領域への書き込みと読み取りの保護。

マッピング領域を他のプロセスと共有したくないので MAP_PRIVATE フラグを使用し、ファイルをマップしていないので MAP_ANONYMOUS を使用します。

ファイル記述子とオフセットは、同じ原因で 0 に設定されています。

コード例 (プロセス間通信 用):

#include <stdio.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
  int Number = 5;
  int *ptr = mmap(NULL, Number * sizeof(int), PROT_READ | PROT_WRITE,
                  MAP_SHARED | MAP_ANONYMOUS, 0, 0);

  if (ptr == MAP_FAILED) {
    printf("Mapping Failed\n");
    return 1;
  }

  for (int i = 0; i < Number; i++) {
    ptr[i] = i + 7;
  }

  printf("Initial array's values:");
  for (int i = 0; i < Number; i++) {
    printf(" %d", ptr[i]);
  }
  printf("\n");
  pid_t child_pid = fork();

  if (child_pid == 0) {
    // child
    for (int i = 0; i < Number; i++) {
      ptr[i] = ptr[i] * 5;
    }
  } else {
    // parent
    waitpid(child_pid, NULL, 0);
    printf("\nParent:\n");
    printf("Updated array's values:");
    for (int i = 0; i < Number; i++) {
      printf(" %d", ptr[i]);
    }
    printf("\n");
  }

  int err = munmap(ptr, Number * sizeof(int));

  if (err != 0) {
    printf("Unmapping Failed\n");
    return 1;
  }
  return 0;
}

出力:

Initial array's values: 7 8 9 10 11
Initial array's values: 7 8 9 10 11

Parent:
Updated array's values: 35 40 45 50 55

最初にいくつかの値で配列を初期化します。 次に、子のプロセスが値を変更します。

さらに、値は親プロセスによって読み取られますが、マップされたメモリは両方の (子プロセスと親プロセス) で共有されているため、子プロセスによって変更されます。 また、munmap() を使用してメモリ マッピングを削除しています。

著者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

関連記事 - C Function