C++ でシステム コールを作成する
このチュートリアルでは、C++ で書かれたプログラムから write
システムを呼び出す方法について説明します。 まず、システム コール、特に write
システム コールとそのプロトタイプをすばやく更新します。
後で、C++ プログラムからの write
システム コールの呼び出しについて説明します。
C++ でのシステム コール
すべてのオペレーティング システムは、システム コールを通じて一連のサービスを提供します。 これは、コンピューター プログラムがオペレーティング システムからサービスを要求するメカニズムです。
システム コールは、次のサービスを提供します。
- プロセスの作成と管理
- 主記憶管理
- ファイルおよびファイル システムの管理
- デバイスの入出力
- 保護
- ネットワーキング
プログラムが必要とする最も頻繁なサービスは入出力です。 次に、write
システム コールについて説明します。
プログラムは、write
システム コールを介して、基盤となるオペレーティング システムにデバイスへの書き込みを要求します。
write
呼び出しに進む前に、ファイル記述子について理解することが重要です。
ファイル記述子
Unix および Unix ベースのオペレーティング システムでは、ファイル記述子は、ファイルまたはソケットやパイプなどの他の IO リソースを一意に識別する番号です。
通常、ファイル記述子は負でない整数値です。 プログラムは、ファイル記述子を介して IO 用のファイルにアクセスします。
ライブラリ関数は IO を処理し、ファイル記述子をパラメーターとして受け取ります。
最初のステップは、IO 用のファイルにアクセスするために、名前 (ファイルがプログラムのフォルダーにない場合は絶対パス/相対パス) でファイルを開くことです。
open
関数がファイルを開くことに成功した場合 (つまり、同じ名前のファイルが存在し、ユーザーが必要な権限を持っている場合)、ファイル記述子を返します。
int fd = open("abc.txt", O_RDONLY | O_CREAT);
open
関数には 2つのパラメーターがあります。 最初のパラメーターはファイル名で、2 番目のパラメーターは読み取りモード (読み取り専用モード、書き込み専用モードなど) です。
ファイルに対する後続の IO 操作は、ファイル記述子を介して実行されます。
C++ の write
システム コール
write
システム コールは、オペレーティング システム カーネルが提供する最も基本的なルーチンの 1つです。 プライマリ メモリ (バッファ) からファイル (一部のハードウェア デバイスに格納されている) にデータを書き込みます。
write()
システム コールは、buf
が指すメモリ バッファから、ファイル ディスクリプタが参照するファイルに最大 count
バイトを書き込みます。
これは、バイトしか理解できない低レベルの関数です。 クラスのように、write
呼び出しを使用してレコードを書き込むことはできません。
したがって、複雑な I/O を実行するには、高レベルの入出力関数 (printf()
など) が不可欠です。
最初に、データをファイルに書き込むために使用される write
システム コールの構文を見てみましょう。
ssize_t write(int fd, const void *buf, size_t count);
write
関数の 3つのパラメーターの詳細は次のとおりです。
- ファイル記述子
fd
は、ファイルを開く呼び出しから取得されます。 これは整数値です。 値0
、1
、2
は、それぞれ標準入力、標準出力、標準エラーに与えることもできます。 - データが一次メモリに格納されているメモリ内のバッファ
buf
へのポインタ。 - バッファー
buf
からfd
が指すファイルに書き込まれるcount
で指定されたバイト数。
型 ssize_t
および size_t
は、それぞれ、stddef.h
で定義されている符号付きおよび符号なしの整数データ型です。
戻り値
write
関数は符号付きの値を返します。 成功すると、ファイルに正常に書き込まれたバイト数を返します。これは、指定された count
よりも少ない場合があります。
合計書き込みバイト数が count
よりも少ない理由として考えられるのは、出力デバイスのメモリがいっぱいであるか、ソースの書き込みバッファーに書き込む chars
の数が count
で指定された数よりも少ない可能性があります。
エラーの場合、write
システム コールは -1
を返し、発生したエラーを示すために errno
が設定されます。
ここに、write
システム コールを使用してファイルに書き込む完全なプログラムがあります。
#include <errno.h>
#include <fcntl.h>
#include <iostream>
extern int errno;
using namespace std;
int main() {
int fd, count;
fd = open("abc.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
cout << "File descriptor = " << fd << '\n';
if (fd == -1) {
// print which type of error have in a code
printf("Error Number % d\n", errno);
// print program detail "Success or failure"
perror("Program");
}
char buff[] = "This is a test program to check write system call.";
count = write(fd, buff, 50);
if (count == -1)
cout << "Error writing in file";
else
cout << "Number of bytes written to the file: " << count << '\n';
close(fd);
return 0;
}
最初のヘッダー ファイル fcntl.h
には、write
システム コールがあります。 2 番目のヘッダー ファイルにはエラー関数があります。
open
関数呼び出しでは、新しいファイル名 abc.txt
を書き込みモードで作成します。 ファイルは以前に存在する可能性がありますが、O_TRUNC
を使用すると、以前の内容が削除され、新しい空のファイルが作成されます。
コード 0644
は、ファイルのパーミッションを示します。 次に、if
条件は、ファイルが正常に開かれたかどうかをチェックします。
失敗した場合、エラーメッセージが表示されます。
次に、サンプル テキストを含む文字配列 (バッファーとして使用) を作成しました。 最後に、ファイルに書き込みます。
3 番目のパラメーターは 50
で、buff
配列から書き込む文字数を指定します。
count
は write()
API 呼び出しから返される整数値です。 失敗した場合、値は -1
になります。 したがって、カウントを確認し、それに応じてエラー メッセージを出力します。
書き込み操作が成功した場合、count の値は正になり、if
条件はファイルに正常に書き込まれた合計バイト数を示します。
最初の出力値 3
は、ファイルが正常に開かれたことを示しています。 2 行目の 50
は、50 バイトすべてが正常に書き込まれたことを示しています。
次に、open
ステートメントを変更しました。
fd = open("abc.txt", O_RDONLY | O_CREAT | O_TRUNC, 0644);
O_WRONLY
を O_RDONLY
に置き換えたことに注意してください。その結果、出力は次のようになります。
File descriptor = -1
Error Number 13
Program: Permission denied
Error writing in file
コンテンツを切り捨てて既存のファイルを読み取りモードで開くことはできないため、open
操作は失敗しました。
失敗の結果、ファイル記述子が -1
になっていることがわかります。 また、書き込み操作が失敗します。
write
システム コールの前にファイルを閉じると、結果として write
システム コールによる操作が失敗します。 この場合、出力は次のようになります。
File descriptor = 3
Error writing in file
ここでは、ファイル記述子は -1
ではありませんが、ファイルは閉じられています。 したがって、write
システム コールは失敗します。
write
システムコールによって返される値は -1
です。 したがって、エラー メッセージが出力されます。