昔からある、strcat(a,b ) などは、aの後にbを追記していくので、前持ってaのバッファをb分拡張しておかないといけない。
今風に云えば事前にバッファを拡張しないとオーバランしてしまい、mallocのようなヒープを使っていれば free した途端にドカンとくる訳だ。
と書くと面倒なもののように思えるが、
実は・・・
char * myStrCat( char * a, char * b) {
int lenA = strlen( a );
int lenB = strlen( b );
char * buf = malloc( a + b + 1 ); // +1 は NULコード分
if ( buf == null ) {
exit 1010; // 鞄がパンパンです
}
strcat(buf,a);
strcat(buf,b);
return buf;
}
みたいにラップして使うのが前提の関数だった。
勿論、使い終わったら、自己責任で、慎重にfreeしなければいけないので、
void myFree(char *buf) {
if ( buf == NULL ) return ;
free (buf);
}
安心のために、なんかも必要だ。
※一気に書き上げたので動くかどうかはかなり怪しい。以下のソースも同様。
バッファしながらファイルに書き込むなら・・・
#define BUF_SIZE (1024)
static char * buf = null;
int writeFile( File * file, char * text )
{
int count = 0;
if( buf == null ) {
buf = malloc ( BUF_SIZE );
memset(buf, 0, BUF_SIZE);
}
int lenUse = strlen(buf);
int lenText = strlen(text);
while( (lenUse + lenText) > BUF_SIZE ) {
//空いてる分に少し詰めて
strncat(buf,text, BUF_SIZE – lenUse);
count += BUF_SIZE – lenUse;
//ファイルに書き出す
write(file,buf,BUF_SIZE);
//バッファに書き出していない部分にポインタを移動する
text += BUF_SIZE – lenUse;
//残りのバイト数を数える。
lenText = strlen(text);
//バッファをクリアする
memset(buf, 0, BUF_SIZE);
lenUse = 0;
}
//もう、バッファに一気に書き込めるので・・・
strcat( buf, text );
count += lenText;
//書き込んだバイト数を返す
return count;
}
そうそう
void bufFlush (File * file ) {
if( file == NULL ) return ;
int lenUse = strlen(buf);
write(file,buf, lenUse);
free(buf);
buf = NULL;
}
も必要だ。
見るからに、少しイジれば簡単にボロが出そうなソースだ。
よく考えてエレガントに作ろうとしても、そもそもが strcat ベースなので、基本的にクリティカルなものになっている。
まさに『見るだけ!触るな!混ぜるな!』~を地で行くシロモノである。
こんなソースを コードレビューして、あーでもない こーでもないとイジれば、
どんな結果が飛び出すかは、判り易いというものだ。
しかし、チャンと動いてしまえば、もう中身は気にしなくて良いので、ドンドン流用できる。
これがライブラリィの良いところである。
そう、こんな汚いソースなんて今時ある訳が無いとか思うかもしれない。
しかし、クラス・ライブラリィとか オペレーター オーバライトの実装などは大抵こんなもんである。
まさに知らぬが仏な日常なのですよ。(大笑)
では、こんなソースは無くして、可変長バッファクラスでも導入して、綺麗にすればよいのかといえばそうはいかない。
結局は、誰かが、バッファの中の使用バイト数は?とか、何バイト書き込んだら安心か?っと、誰かが責任を持つしかないのだ。
strcat を使おうが memcpy を使おうが バッファを配列にしようが、所詮は同じなのだ。
まぁ、その辺は、コンパイラやインタプリターの実装とか見ると、気が遠くなるかもしれないが、
実は、上の様なソースとあまり変らないのだ。
結論から言えば、
ちゃんと動いているものは、もう触らない。
クラスとかライブラリィとか綺麗にラッピングして神棚に飾っておくのが一番いいのである。
そして、使っているうちに、スレッド・セーブじゃなかったので調整!mutex とか 使いつつも、
ワードセグメントやアーリーライトやミニマム・セグメント・サイズにまで気を配りながら、CPUやTLBの仕様もチェックしつつ、
Linuxの仮想記憶はハードウェアの上のラッパーでしかないのだから・・・ダブル・フォルトが出てからが勝負!
先の+1を+2や+15に変えながら、最速を目指すのである。
そう全てが出来上がるまでの毎日が結合テスト日和なのだ。
これほど、テストされ信頼を勝ち得えることが出来て、性能まで肌で感じられる開発技法が他にあるだろうか?
勿論テストは全自動化しなくてはいけない。気が付けばテスト・パターンは山のように出来ているのだ
まず最初の方のテスト項目は
- a = NULL の場合に いきなりクラッシュする。
- a = 16の場合には、環境変数のリストが返ってくる。
- a= -4096の場合には、得たいの知れない中身が返ってくる。
から始まるのだから・・・(笑)