へっぽこ社会人4年生がプログラミングを頑張る

へっぽこ社会人4年目がプログラミング系統を中心に書きたいことをつらつらと書きます

システムコールで遊んでみる その3

今回はlseekというシステムコールについて、適当に書いていこうと思います。 lseekは、ファイルポインタを指定の位置に動かします。 プログラム例を以下に示します。

#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  int fd;
  char buf[65536];
  
  if(argc != 2) {
    write(STDERR_FILENO, "ERR\n", 4);
    return 1;
  }
  
  fd = open(argv[1], O_RDONLY);
  read(fd, buf, 3);
  write(STDOUT_FILENO, buf, 3);
  write(STDOUT_FILENO, "\n", 1);
  
  lseek(fd, 0, SEEK_SET);
  read(fd, buf, 3);
  write(STDOUT_FILENO, buf, 3);
  write(STDOUT_FILENO, "\n", 1);
  
  return 0;
}

また、fileというファイルには、以下のように記述して保存しておきます。

(ファイル名は何でも良いですが...)
0123456789
abcdefghij
ABCDEFGHIJ

上に記したプログラムを走らせると、実行結果は以下の通りになります。

実行プログラムはlseekとします。
$ ./lseek file
012
012
$
ちょっと解説(っぽいもの)

システムコールlseekを利用するには、 unistd.hをインクルードする必要があります。成功でファイルの先頭から指定したファイル位置までのバイト数を、失敗なら-1を返します。

lseekのインタフェースは以下の通り。

  • lseek
    • off_t lseek(int fd, off_t offset, int whence);

lseekの第1引数fdは、ファイルディスクリプタです。 第2引数のoffsetは第3引数whenceで指定した基準から何バイト離れているかを指定します。 第3引数whenceは以下のように指定します。

  • SEEK_SET
    先頭からoffsetバイト離れた場所に移動
  • SEEK_CUR
    現在位置からoffsetバイト離れた場所に移動
  • SEEK_END
    ファイルサイズoffsetバイト加えた場所に移動

上のプログラム例では、openした後にreadで3バイトbufに格納しています。 その後にlseekを呼び出しているのですが、whenceにはSEEK_SETを格納し、offsetは0、つまり、ファイルの先頭から0バイト離れた(言い換えると、ファイルの先頭)場所にファイルポインタを移動します。 lseekでファイルポインタを移動させたあと、再びreadを呼び出し、3バイト分bufに格納しています。 なので、2回ファイルの先頭の3文字(012)が表示されています。

whenceSEEK_CURを指定して実行すると、

012
678

と表示されます。

offset-3を、 whenceSEEK_ENDを指定して実行すると、

012
HIJ

と表示されます。

ファイルの最後には改行文字が入っていないことが前提です。

今回は、ファイルの最後から3文字戻るという意味で、offsetに-3を指定しました。

詳しくは、man 2 lseekとターミナルに入力してマニュアルを呼び出してみてください。

とりあえず、今回はここまで。 次はpipeについて書くか、forkについて書くか、 はたまたstatについて書くか迷っています...