正誤表
読者の方からメールでご指摘いただいたりしております。大変申し訳ありません。
・main()はvoid main()ではなく、int main()ではないか、という問題があるのですが、ANSI Cではint main()で、main()のreturn値がプログラムの終了ステータスとなる、となっています。従ってANSI C準拠ではint main()とすべきです。著者はK&R時代からの癖で、終了時は基本的に明示的にexit()を使用する為、あえてvoid main()としています。割り込み関数でexit()する場合と、main()が終了する際で、終了ステータスの返し方が異なるのはいまだになじめない気分もあります。ANSI C準拠コンパイラではvoid main()は警告が出ますので、気になる方はint main()に置き換えてください。また、リターンの不要な関数はプロトタイプ宣言が不要なintに、という記述もANSI C準拠コンパイラではプロトタイプ宣言が無いと警告が出るものがほとんどで、実際はプロトタイプ宣言すべきと思いますが、テストプログラムなど、試行錯誤を行っている間はとにかく動かすことが先決で、その意味でプロトタイプ宣言を省略するのも無意味な行動では無いと思っています。プロトタイプ生成は自動生成も簡単に自作できるものですので、ある程度方針が固まってからでも自分で管理している範囲では良いと思います。本書は文法書ではありませんので、ご自分のスタイルに合わせてご利用ください。
・入門編の「strtok,2バイト文字について」と「2バイト文字」は二つに分かれていますが、本来連続した内容で、1つの章になるべきものです。組み合わせてお読みください。
・202ページの一番下の行の"="は"+="の間違いです。
token->size=TOKEN_ALLOC_SIZE;
token->size+=TOKEN_ALLOC_SIZE;
・57ページの下から9行目 va_strart(args) -> va_start(args)
・84ページの上から8行目 pipe_c2c -> pipe_p2c 、 84ページの下から14行目 pipe_p2p[R] -> pipe_c2p[R] 、 84ページの下から4行目 pipe_p2p[W] -> pipe_c2p[W]
・108ページの下から2行目の prcgen -> rpcgen 、 109ページの最上行の prcgen -> rpcgen
・149ページのmain関数にbytes変数の定義が無いです。int bytes;と宣言してください。なお、このソースはLINUXなどOSによってはFIONREADが定義されているsys/fileio.hが無い場合があります。1バイト単位の入力は設定可能ですが、ノンブロッキングとして使いたい場合は、select()で入力状態をチェックするか、178ページで紹介しているfcntl()を使う方法も検討してみてください。あるいは、sys/ioctl.hを代わりにインクルードするとうまく行く環境もあるようです。さらに、このサンプルで標準出力のバッファリングにより数文字入力しないと表示されない、というご指摘もいただいております。先頭で、setbuf(stdout,NULL);を行い、標準出力のバッファリングをOFFにすることですぐに表示されるようになります。
・実践編のサーバで、SIGCLDシグナルでwait()していますが、非常に大量にクライアントが同時接続・切断を行うと、シグナルの数と実際に終了した子プロセスの数が合わなくなります。MainLoop()のループ内で、ブロックしないwaitpid()などを使って終了ステータスを定期的に得るようにしないと、ゾンビプロセスが残ってしまいます。
・34ページで、GetMapAddr()をunsigned char **にしていますが、これではmain側でアクセスできません。
unsigned char (*GetMapAddr())[100] { return(Map); }
とし、main側は、
unsigned char (*MainMap)[100];
unsigned char (*GetMapAddr())[100];
void main()
{
.
.
MainMap=GetMapAddr();
.
}
とするのが正しいです。
・105〜106ページの、do_rls()は動くOSもありますが、Solaris2Xなどで動かないことをご指摘いただきました。引数で与えられてバッファにディレクトリ内容を格納し、リターンするのが上手く出来ないOSがあるようで、1回は動いても2回目から動かない、という現象などが起きます。do_rls()内部でスタティックに応答用のバッファを用意して、それを応答するようにすれば使えるようになります。また、ディレクトリ内容の格納部分が間違えています。下記のソースを参考にしてください。
char *do_rls(char *buf)
{
DIR *dirp;
struct dirent *dp;
static char ret_buf[BUF_SIZE];
char tmp[512];
dirp=opendir(buf);
if(dirp==NULL){
strcpy(ret_buf,"opendir error");
return(ret_buf);
}
strcpy(ret_buf,"");
while(dp=readdir(dirp)){
sprintf(tmp,"%s/%s\n",buf,dp->d_name);
strcat(ret_buf,tmp);
}
closedir(dirp);
return(ret_buf);
}
・201ページのGetToken()にミスがありました。jでのループで、continue;の前にj++;が必要です。
if(buf[i]=='"'){ /* "文字列 */ for(j=i+1;j<len;j++){ /* SJIS漢字1バイト目、エスケープ */ if(issjiskanji(buf[j])||buf[j]=='\\'){ j++; continue; } if(buf[j]=='"'){ break; } } i=j; } if(buf[i]=='\''){ /* '文字列 */ for(j=i+1;j<len;j++){ /* SJIS漢字1バイト目、エスケープ */ if(issjiskanji(buf[j])||buf[j]=='\\'){ j++; continue; } if(buf[j]=='\''){ break; } } i=j; }
#include <stdio.h>
#include <stdarg.h>
int debug_print(char *fmt,...); /* プロトタイプ宣言 */
int debug_print(char *fmt,...)
{
va_list args;
char buf[256];
va_start(args,fmt);
vsprintf(buf,fmt,args);
va_end(args);
fprintf(stderr,"DEBUG[ %s ]\n",buf);
return(0);
}
・142ページのhan2zen()をSJISで使う場合、switch文の前にSJIS1バイト目かどうかのチェックを行い、スキップする処理を入れないと文字化けします。SJIS2バイト目はASCIIとコードが重なりますので。
#define issjiskanji(c) ((0x81 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0x9f) \ || (0xe0 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfc))
をデファインし、
int han2zen(char *str){
char *buf,*p,*ptr;
buf=(char *)calloc(strlen(str)*2+1,sizeof(char));
for(ptr=str,p=buf;*ptr!='\0';*ptr++){
if(issjiskanji(*ptr)){
/* SJIS漢字1バイト目の場合 */
*p=*ptr;
p++;
ptr++;
*p=*ptr;
p++;
*p='\0';
continue;
}
switch((int)*ptr){
case ' ': strcpy(p," ");p+=2;break;
case '!': strcpy(p,"!");p+=2;break;
と言う感じに追加します。
・31ページのソースで、高速化のため、Map[y][x]で、と説明しているにもかかわらず、ソース中でMap[x][y]と使ってしまっています。Map[y][x]と修正します。この先のソースではMap[y][x]と正しく扱っています。
from 2000/9/13