All articles in c-language

パッド

ウィンドウは物理画面や親ウィンドウの範囲内に収まっていなければならない.パッドとはそのような制約なしに自由な大きさで作成できる論理画面である.パッドの利点パッドの生成,操作,削除なんちゃってless パッドの利点 ウィンドウはかならず画面内に収まっていなければならないので,「後で表示するかもしれないが今は画面外にあるデータ」はなんらかの方法で確保しておくか,表示するときに取得,生成などをしなければならない.後者の場合は処理が複雑になりがちである.前者はシンプルに実装できそうだが,リソースを食いそうだ.パッドはこの前者の実装に便利である.すなわち,パッドを使用すると論理画面にまとめて表示データを格納しておいて,必要な分だけ物理画面で表示することが可能になる.しかも簡単に. パッドの生成,操作,削除 なんちゃってless スクロールのところでなんちゃってmoreを作成した.そしてパッドには上記のような利点がある.ということで,パッドを使用するサンプルはなんちゃってlessにしてみた. これはlessっぽい機能を持つ.C-n,C-p,C-v,M-vで画面を上下にスクロールする.そして’q’で終了する.また,画面右端での折り返しはしない.そのかわりC-f,C-bでの左右のスクロールを可能にしてみた.ちょっと残念なのが,冒頭のいくつかのdefine文だ.たぶんどっかのヘッダなどで定義されていると思うのだが,発見できなかった.また,ハマった点は,最初はrefreshしてからでないといきなりprefreshしても起動直後になにも表示されないということだった(サンプル中,main関数のswitch文の手前).ただし,何も表示されていない状態でキーを押すとファイルが表示される.

popenとpclose

パイプのopenとclose.popenとpclose読み込む書き出す popenとpclose popenとpcloseは指定したsystem関数にパイプ機能を加えた感じで使用できる.実際shell経由で引数のコマンドを渡すので,オーバーヘッドは大きいがワイルドカードなどを使用できる.で,パイプを使用すると,あるコマンドの出力を別のコマンドの入力に使用できる.例えばdmesg | headでは,dmesgの出力がheadの入力となりそしてそのheadの出力が端末に出力される. 読み込む popenはファイルストリームを開く.pcloseは閉じる.popenではファイルストリームが読み込み用か書き込み用かどちらかを選択する.読むか書くかと聞かれたら,なんとなくまずは読んでみたい気がするのは私だけだろうか.読み込み用で開く場合,popenしたプロセスはコマンドラインでは|の右側ということになる.以下,popenで読み込み用パイプストリームを開いた場合のサンプル. popenの第二引数に”r”を指定すると読み込みモードでパイプをオープンする.そしてこのとき読み込みようのファイルストリームが返る.失敗するとNULLを返す.以下実行結果.2003年 4月10日木曜日21:50:48JST 書き出す 読んだら書きたい.書き込み用でパイプをオープンしたプロセスはコマンドラインでは|の左側ということになる.以下サンプル. popenの第二引数に”w”を指定するとパイプを書き込みモードでオープンする.そして書き込みようのファイルストリームを返す.失敗するとNULLを返す.以下実行結果.Message: # ####################################################################################### ### ## #### ################# #### #### … More popenとpclose

セマフォ

共有メモリの話題に入る前の準備としてセマフォについて記述する.同期の問題セマフォとはセマフォを使ってみるセマフォと共有メモリ 同期の問題 二つのプロセス(もしくはスレッド)A,Bが共有する変数xがあったとする.そしてA,B両者がxに1を足すとする.xが0なら処理後のxの状態が2になっていることを期待してみる.Aがx(=0)の値を読み込む.Aがx(=0)に1を足してそれをxに書き込む.Bがx(=1)の値を読み込む.Bがx(=1)に1を足してそれをxに書き込む.この時x=2.上は「たまたま」正常なタイミングで動作した場合である.もしかしたら以下の状況なるかもしれない.Aがx(=0)の値を読み込む.Bがx(=0)の値を読み込む.Aがx(=0)に1を足してそれをxに書き込む.Bがx(=0)に1を足してそれをxに書き込む.この時x=1.期待に反してx=1となってしまった.これは「たまたま」プロセスの切替えタイミングが悪く,同期をとって処理すべき変数xに対してA,Bが非同期で処理してしまったから起こった現象である.このような処理をクリティカルセクションという.誰かがxをクリティカルセクションを処理しているときに,別の誰かはxを処理できない様にする必要がある. セマフォとは 上の問題を解決するために,ロック変数yを考えてみる.変数yが0の時は別のプロセスはxに対して処理をせず,1なら処理をする.したがってA,Bはxに対して処理する前にyをチェック,変更する.先のタイミングが悪かったパターンは以下のようになる.Aはy(=1)を読み込む.Aはyが1なのでこれを0にする.Aがx(=0)の値を読み込む.Bはy(=0)を読み込む.Bはyが0なので待つ.Aがx(=0)に1を足してそれをxに書き込む.Aはyを1に戻す.Bはy(=1)を読み込む.Bはyが1なのでこれを0にする.Bがx(=1)の値を読み込む.Bがx(=1)に1を足してそれをxに書き込む.Bはyを1に戻す.この時x=2.これでうまくいった.が,よく考えるとyに対してもまた最初のxと同じ状況が発生し得る.これではきりがないので,それを処理する間プロセスの切替えがおこらない何かが必要になる.これがセマフォ(semaphore)である.セマフォはDijkstraが発表したらしい.先のyがセマフォだったとすると,あるプロセスがyを読み込んで値を変更するまでの間,他のプロセスはyに対して処理しないことが保証されている.すなわちセマフォに対する処理はアトミックであることが保証されている.セマフォについてまとめてみた.0か正の整数をとる.waitとsignalという二つの操作だけが可能.waitをしたとき,値が1より大きければ値をデクリメントする.0ならば待つ.signalをしたとき,値が0より大きくなるのを待っているプロセスがあれば,そのプロセスを再開する.なければ値をインクリメントする.バイナリセマフォは0と1の二値をとる.汎用セマフォは0と複数の正の値をとる(例えば0,1,2).こうすると,クリティカルセクションの処理は以下のようになる.セマフォにwait操作をする.クリティカルセクションの実行.セマフォにsignal操作をする.これで問題は解決する. セマフォを使ってみる セマフォを使用するための関数には以下の3つがある.int semget(key_t key, int nsems, int semflg)keyで指定したnsems個からなるセマフォ集合の識別子を取得する.semflgはオプションでパーミッションなどもここで設定する.semflgでIPC_EXCLを指定するとセマフォが一意となることが保証される(keyがセマフォのために既に使用されていればsemgetは失敗する).int semop(int semid, struct sembuf *sops, unsigned nsops);semidで指定したセマフォ集合の操作のメンバを操作する.sopsはセマフォに設定したい値を持つsembuf構造体のnsops個の配列である.int … More セマフォ

bzlibでbz2ファイルを読み書きしてみる

bz2はメモリを喰うがzlibより圧縮効率がよいらしいので,そのライブラリbzlibを試してみた.bzlib.h圧縮エラーメッセージの取得解凍コンパイルと実行 bzlib.h 圧縮 データをbz2形式圧縮してファイル出力するサンプルを以下に示す. include include include define BZ2_MODE “wb” intmain(int argc, char *argv[]){if (argc != 4){fprintf(stderr, “Usage : %s … More bzlibでbz2ファイルを読み書きしてみる

BIOとBase64

BIOはOpenSSLにおけるフレームワークにおける抽象データ型で,暗号化や符号化,ファイルやネットワークといった入出力の詳細をアプリケーションから隠蔽する.で,このフレームワークのもとで実装されているBase64コーデックを試してみた.BIOって何だ?base64エンコードするサンプルbase64デコードするサンプルサンプルの実行 BIOって何だ? BIOはOpenSSLにおける入出力関連のフレームワークにおける抽象データ型である. BIOを使用することにより,アプリケーションでは変更不要なある「お決まりの形式」でプログラミングしつつ,容易にファイル/ネットワークとか,暗号化形式や符号化形式を切替えることができる. さらに,BIOはチェインを組むことができ,例えば暗号化して符号化してネットワークに出力するというBIOのチェイン(このチェイン自信もBIO型となる)を作成して書き出すのも,データをそのままファイルに書き出すのも同様の記述によって表現できるようになる. 上の図はBIOのクラス図である. BIO_f_md,BIO_f_base64,BIO_s_file,BIO_s_connectは実際には関数だが,イメージを掴みやすくするために,上のように記述した. man bioによると,BIOには二種類ある.ソース/シンクBIOソケットBIOとか,ファイルBIOといった,データのソース(源),シンク(宛先)を実装したBIO.フィルターBIO暗号化など,他のBIOからデータを受け取り,別のBIOにデータを渡すフィルターの役割を果たす. フィルターBIOに格納されているデータが変更されるかどうかは,BIOの実装やオペレーションによる. base64エンコードするサンプル では,実際にBIOを使用したプログラミングを試してみる. 今回はbase64でエンコードするサンプルとデコードするサンプルを作成してみる. まずはエンコード. base64デコードするサンプル 次にデコードのサンプルを示す. サンプルの実行

OpenSSLでRSAを試してみる

OpenSSLにはRSAのキーペアを作成し,これを使用して暗号化,復号する機能や,キーをPEM形式で入出力する機能があるのでためしてみた.概要キーペアの作成キーのダンプ出力キーのPEM形式出力エラーメッセージの出力PEM形式キーファイルの読み込み暗号化と復号サンプルの実行 概要 今回は,OpenSSLで以下の作業をする.RSAキーペアの作成RSAは公開鍵方式なので,その公開鍵と秘密鍵を生成する.RSAキーをPEM形式で入出力生成したRSAの公開鍵と秘密鍵をPEM形式でファイルに出力したり,PEM形式のキーデータを読み込んだりする.RSA暗号化と復号RSAキーペアで暗号化と復号を行う.具体的には,キーペアを作成してPEM形式出力するサンプルと,PEM形式キーファイルを読み込んでRSA暗号化,復号を行うサンプルを作成してみた. キーペアの作成 では,キーペアを作成してPEM形式出力するサンプルを以下に示す. キーのダンプ出力 キーのPEM形式出力 エラーメッセージの出力 PEM形式キーファイルの読み込み では,PEM形式キーファイルを読み込んでRSA暗号化,復号を行うサンプルを以下に示す. 暗号化と復号 サンプルの実行

コマンドライン引数の取得とgetopt

コマンドライン引数を取得する方法と,それを簡単に行なうライブラリ関数getoptについて.引数の取得とりあえず引数を取ってみるgetopt 引数の取得 いろんなコマンドはいろんな引数をとる.int main(int argc,char *argv[])のargcが引数の数でargvが引数の値である.0番目の引数の値はプログラム自身の名前である. とりあえず引数を取ってみる 次のプログラムは全ての引数を表示するだけのものである. include int main(int argc,char *argv[]){int i; for(i=0;i<argc;i++){fprintf(stdout,”arg %d is %s\n”,i,argv[i]);} exit(0); }これを実行すると以下の感じになる.$> … More コマンドライン引数の取得とgetopt

コマンドライン引数の取得 その2

関数getopt_longは長い形式のオプションの取得に便利な関数である.これはGNU拡張らしい.長いオプションは大抵–で始まる.getopt_long外部変数オプションの設定サンプルgetopt_long_only getopt_long getopt_longはgetoptを拡張して–で始まる長い形式のオプションを解釈できるようにした関数である.POSIX準拠ではなく,GNU独自のものらしい.長い形式のオプションは一意に決まる限り短く省略できる.例えば,–foo –foovarの二つのみをオプションに持つコマンドがあった場合,–foovarは一意に決まる省略形–foovでも解釈される.int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int longindex); 各引数について以下に示す. argc,argv[]main関数の引数をそのまま渡す.*optstringgetoptと同様,短い形式のオプションを示す.*longopts長い形式のオプションを示す構造体optionの配列.longindex マッチした長い形式のオプションに対するlongoptsのインデクス.getopt_longのさらなる説明はオプションを示す構造体optionの説明が中心になる.struct … More コマンドライン引数の取得 その2

forkとwaitとゾンビプロセス

forkはプロセスのコピーを作成する.そしてwaitで待つ.処理の流れが一本から複数に分かれる様がフォークみたいだからforkなのだろうか.forkで何がコピーされるのかforkのサンプルwaitwaitのサンプルゾンビプロセスについて forkで何がコピーされるのか forkはそれを実行したプロセスの子プロセスを作成する.子プロセスは親プロセスのコピーである.プロセスをどこまで実行したか(プログラムカウンタ?)もコピーされるので,子プロセスはforkの返り値が返るところから実行される(と,思う).あと,ファイルディスクリプタなどもオープンされていればそのままコピーされる.コピーされないのはpidやppidとファイルロックやサスペンド中のシグナルぐらいだろうか.そして,そのforkの返り値によって,プロセスは自分が親プロセスか子プロセスかを知ることができる.成功すれば子プロセスには0が返り,親プロセスには子プロセスのPIDが返される.エラーの時は親プロセスに-1が返り,子プロセスは生成されない.-1が返ったときには,errnoに値がセットされているはず.EAGAIN親プロセスのページ・テーブルのコピーと子プロセスのタスク構造に生成に必要なメモリをfork が割り当てることができなかった.ENOMEMメモリが足りないために,forkは必要なカーネル構造体を割り当てることができなかった. 子プロセスはPIDが固有で,PPIDを親プロセスのPIDに設定されている以外は親プロセスのものがコピーされる. forkのサンプル 子プロセスを生成して子プロセスの親プロセスがそれぞれ自分と相手のPIDを表示するサンプルを作成してみた. 実行すると,以下のようになる.fork donefork donechild process. pid = 1261. my ppid = 1260parent process. pid … More forkとwaitとゾンビプロセス

sigaction

sigaction関数はsignal関数よりもより細かい制御ができる.sigactionはX/Open仕様ではsignalよりも信頼できるとして推奨しているらしい.sigaction構造体サンプルsigset_tsigactionの仲間達サンプル2sigactionのメモ sigaction構造体 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);sigactionの引数について以下に示す.signumsigaction構造体を設定するシグナル.act設定するsigaction構造体.oldact設定前(変更前)のsigaction構造体.sigaction関数は成功すれば0,失敗すると-1を返す.sigaction関数ではsigaction構造体を引数にとる.この構造体がsignal関数との違いの鍵を握っている.以下,/usr/include/bits/sigaction.hより sa_sigactionは3つの引数を取る関数で,そのうちの一つsiginfo_tは構造体になっていて,またたくさんのフィールドを持つ.面倒なのでここでは書かないが,こいつを使うとさらに細かい制御ができそうな雰囲気を感じた. サンプル sigactionを使ったサンプルを以下に示す. sigset_t sigactionの仲間達 仲間かどうかは知らないが,とにかくman sigactionとすると一緒に出て来る関数が三つある.int sigprocmask(int … More sigaction