ふつうのLinuxプログラミング Reading Vol.1
社会人になってしばらく経つが、C言語やLinuxプログラミングは学生時代からほとんど触ってなかったので、 OSのことを学びながらかんたんなLinuxプログラミングができるこの本で勉強している。 Linuxの概念やシステムコールから丁寧に書いてあるし、要点を抑えて読みやすく書いてくれているのでスラスラ読める。 勉強メモを残していく。
Amazon.co.jp: ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道: 青木 峰郎: 本
1.2 プログラミング環境の準備
Linuxを構成する3つの概念
- ファイルシステム
- プロセス
- ストリーム
この3つを理解しよう。
Linuxをインストール
Ubuntuか迷ったけど、仕事ではRedhat系が普通なのでFedoraを。 12/10にFedora21がリリースされたというので早速21を入れる。 3つのエディション、Server,Workstation,Cloudとあるが、無難そうなWorkstationを入れる。 今更気づいたが、"Fedora Core"は6まででそれ以降は"Fedora"らしい。
1.3 gccを使ったビルド(1)
gccでビルド
適当にhello world作成。 下記のようにビルド
gcc hello.c
なにもオプションを付けないと a.out が出力される。ここらへん全然覚えてなかった。 ./a.out で実行することができる。
1.3 gccを使ったビルド(2)
出力されるプログラムのファイル名を指定するオプション
gcc -o hello hello.c
バグとデバッグ
- segmentation faultで強制終了するのが最も気づきやすいバグ
- segmentation faultはNULLポインタを渡してしまった時などに起こる。間違いなくバグ。
- デバックには下記の方法がある
- gcc -Wall オプションで細かく警告 gccでプログラムをビルドする時は常に-Wallをつけておくべき。
コンパイラによる最適化
- 最適化 = 実行速度を出来るだけ速くする
- Oオプション 最適化のゆるい順に-O1, -O2, -O3 基本は-O2(O3はバグが多いらしい。)
1.5コマンドライン引数
glob
「*」のことをglob(グロブ)という。
glob, globfree - パターンにマッチするパス名を見付ける。glob() によっ て確保されたメモリ領域を解放する
グロブはShellの機能で、プログラムが展開しているわけではない。(Windowsはプログラムが解釈)
1.6 開発環境の話
1.7 情報の集め方
- manのセクション
1.ユーザーコマンド 2.システムコール 3.ライブラリ関数 4.デバイスファイルなど
5.ファイルフォーマット
6.ゲーム
7.規格など
8.システム管理用コマンド
最初にヒットしたもののセクションしかでない。
2.1 オペレーティングシステム
UNIXとUNIX風OSの歴史
カーネル
- Fedora21の場合 /boot/vmlinuz-3.17.7-300.fc21.x86_64
システムコール
2.2 ライブラリ
ライブラリとライブラリ関数
- システムコール以外にも使える関数→ライブラリ関数(printf()やstrlen()など)
- ライブラリ関数はライブラリに収められている
- Linuxのライブラリの実体はファイルであり、その中には関数(のコード)が入っている。
- 関数をリンクしておくとその関数を呼び出すことができるようになる
システムコールとライブラリ関数
- システムコールとライブラリ関数の区別は曖昧。昔はシステムコールだったが今はライブラリ関数で実装されている場合もある。
- 上記の逆もある。
- manを見るときには注意。printfやwriteはコマンドのものと、ライブラリ関数のものもある。
libc
- standard C library = libc
- libcの中核、libc.so.6はfedora21には下記にあった。
/usr/lib64/libc.so.6
3.1 ファイルシステム
ファイル
- 広義のファイル
わかりやすく言うとlsで表示されるファイル - 狭義のファイル(regular file)
3.2 プロセス
- プロセス=動作中のプログラム
3.3 ストリーム
- stream = byte stream バイト列が流れる通り道のようなもの
- ハードディスクやキーボードのやりとりも、バイト列のやりとりなのでカーネルがストリームを作りプロセスへ受け渡す。
バイト列が出たり入ったりするものならば、何でもストリーム。
パイプ
ストリームはプロセスtoプロセスでも問題ない。このようなストリームをパイプという。 * 各コマンドを独立したプロセスとして同時に実行する * そのプロセス間をストリーム(パイプ)でつなぐ という仕組み
プロセス間通信
- プロセス同士がストリームを通じてデータをやりとりしたり意思の疎通を図ること。
4.1 ユーザとグループ
ディレクトリのパーミッション
- 読み込み可能の場合、その中のファイルをリストできる
- 書き込み可能の場合、その中に新しいファイルを作成したり削除したいrできる
- 実行可能の場合、その中のディレクトリの中のファイルにアクセスできる
ディレクトリが実行可能でない場合、その中にあるファイルのパーミッションには関係なく、一切アクセスできなくなる。
クレデンシャル
プロセスの属性としてのユーザーのことをクレデンシャル(credential)と呼ぶ。
ユーザデータベース
- ユーザー情報は /etc/passwd にある。
- グループIDとグループ名のつながりは /etc/group
4.2 シェルと端末
コマンドライン = シェルと端末(shell terminal)
端末の歴史
UNIXの黎明期に大量に使われていたテレタイプ(teletype) 紙ベースでやりとり。 UNIXでは端末のことをttyというが、TeleTYpeからきている。
5.2 ファイルディスクリプタ
5.6 catコマンドを作る
- read, write, open, closeでストリームにアクセスするシステムコールは大体語れる。
- perror(3) 標準エラー出力にエラーを吐く
- システmコールが失敗した時は、失敗した原因を表す定数がグローバル変数errnoにセットされる
5.7 その他のシステムコール
ファイルオフセット
read()システムコールを呼ぶと、前回の続きから始まるが、これは位置を記憶しているから。 ファイルオフセットはシステムコールで操作できる。代表的なものに lseek() がある
5.8 練習問題
- ファイルの指定があればそのファイルを使う、 指定がなければ標準入出力を使う
- functionの共通化を図る上で下記のように実装する
- do_cat関数は引数にfile*型を指定できるようにする
- 実行時引数があるかどうかを最初に判断
- 標準入力を受け付ける場合は、"stdin"をdo_catに渡す。
- do_cat関数内で、fgetcとputcharを使って文字を位置文字ずつ読み込み、出力を行う。