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)
この関数の使用に入る前に、引数について説明しましょう。
-
address
- マッピングに使用する優先開始アドレスを提供します。 他にマッピングがない場合、カーネルは近くのページ境界を選択してマッピングを作成します。それ以外の場合、カーネルは新しいアドレスを選択します。 このパラメーターの値が
NULL
の場合、カーネルは適切と思われる場所にマッピングを配置します。 -
長さ
- バイト数がマップされます。 -
protect
- 許可されるアクセスの種類を制御します。 たとえば、読み取りアクセスの場合はPROT_READ
、書き込みアクセスの場合はPROT_WRITE
、実行の場合はPROT_EXEC
です。 -
フラグ
- マップの性質を制御するために使用されます。 一般的で便利なフラグの一部を以下に示します。MAP_SHARED
- マッピングを他のプロセスと共有します。MAP_FIXED
- システムは、address
パラメータで指定された同じマッピング アドレスを使用することを強制されます。MAP_ANONYMOUS / MAP_ANON
- 匿名マッピングを作成します。MAP_PRIVATE
- このフラグを使用している間、マッピングは非公開になり、他のユーザーには表示されません。
-
filedes
- ファイル記述子はマップされるはずです。 -
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()
を使用してメモリ マッピングを削除しています。