Newsgroups: fj.archives.answers,fj.lang.c From: kitano@crd.yokogawa.co.jp (Kinichi - Kinchan - Kitano) Subject: comp.lang.c Answers to Frequently Asked Questions (FAQ List) in Japanese[4/4] Sender: news@leia.pa.yokogawa.co.jp (Leia news server) Message-ID: Supersedes: Date: Mon, 14 Jul 1997 17:31:37 GMT Reply-To: kitano@crd.yokogawa.co.jp Organization: Yokogawa Electric Corporation, Tokyo, Japan. Followup-To: fj.lang.c Lines: 2097 Archive-name: c-faq-j/part4 Last-modified: 14 July. 1997 ========================= C FAQ 日本語訳[4/4] ========================= 16章 奇妙な問題 16.2a: わけがわからない文法エラーが出て困っている。 プログラムの大部分がコンパイルされないままのように見える。 A: コメントを閉じ忘れてないかとか、 #if/#ifdef/#ifndef/#else/#endif指令が対応するものが抜けてない かをチェックする。ヘッダファイルもチェックすることを忘れてはい けない。(質問2.18, 10.9, 11.29も参照のこと。) 16.2b: どうしてprocedure呼出しがうまくいかないのか。コンパイラはそこ のところを飛ばしているように見える。 A: そのコードは以下のようなものか。 myprocedure; Cには関数しかない。その上、関数呼出しには括弧でくくられた引数 リストが、引数がなくても必要である。 myprocedure(); と書く。 16.3: プログラムが走る前にクラッシュする(デバッガを使って一行づつ ステップ実行で追うとmain()の最初の行を実行する前に死んでしまう)。 A: このプログラムは、非常に大きな(1キロバイトかそれ以上の)ローカ ルな配列を持っているに違いない。多くのシステムでスタックの大きさ は固定だし、(Unixのように)自動的にスタックを動的に割り付けるシス テムでもスタックのサイズが突然巨大になると、混乱する場合がある。 大きな配列を使うときはstaticと宣言したほうがいい(もちろん再帰 呼び出しするたびに新しい配列が必要な場合は除く。こういう場合は malloc()を使って動的に割り付ける。質問1.31を参照のこと)。 (質問11.12, 16.4, 16.5, 18.4も参照のこと) 16.4: このプログラムは正しく動いているように見えるけれど、main()から 抜けるところで、つまりmain()の最後の文の後で、クラッシュする。 なにがこんなことを引き起こすのか。 A: main()のプロトタイプ宣言のおかしくないかとか(質問2.18, 10.9参 照)、setbuf()とかsetvbuf()にローカルのバッファを渡してないかと か、atexit()に登録した後片付けの関数に間違いはないかを調べる。 質問7.5や11.16も参照のこと。 References: CT&P Sec. 5.3 pp. 72-3. 16.5: このプログラム、あるマシンではうまく走るのに、別のマシンだと変 な結果を返す。もっと変なことに、デバッグ用の出力を付けたり外し たりすると症状が違ってくる。 A: おかしくなる可能性のあるものはたくさんある。以下に可能性の高い ものをいくつか示す。 初期化してないローカル変数(質問7.1参照) 整数のオーバーフロー、特に16ビットマシンで、とりわけ a * b / cのような計算の中間結果の桁あふれ(質問3.14も参照 のこと) 未定義の評価の順序(質問3.1から3.4も参照のこと) 外部関数の宣言のし忘れ、特にint以外や"狭い"型を返す関 数や可変個数引数の関数で(質問1.25, 14.2, 15.1参照) ヌルポインタの間接参照(5章参照) 誤ったmalloc/freeの使い方。mallocしたメモリが全部0になっ てるとかfreeした領域がまだ使えると思い込んだり、同じも のを2回freeすること(質問7.20や7.19を参照のこと) ポインタの問題全般(質問16.8も参照のこと) printf()の書式と実引数の不一致、特にlongの整数を%dを使っ て出力しようとする(質問12.9も参照) unsigned intで数えることができる大きさより大きな領域を 割り付けようとすること。とくに、メモリの量が限られてい るマシンで(質問7.16と19.23も参照のこと) 配列の境界の問題。特に小さな一時的バッファで、おそらく sprintf()を使って文字列を構築するのに(質問7.1と 12.21も参照) typedefと実際のデータ型の対応の誤った思い込み。とりわ けsize_t 浮動小数点の問題(質問14.1と14.4を参照) 対象となる具体的なシステムで コードの生成されかたを決 め付けて、こういう使いかたを考え付くとは俺って頭がいい なと思っていることはなんでも 関数プロトタイプを適切に使うことで、これらの問題のかなりの部分 を捕まえることができる。lintを使えばもっと多くの問題を捕まえる ことができる。質問16.3, 16.4, 18.4も参照のこと。 16.6: なぜ以下のコードはクラッシュするのか。 char *p = "hello, world!"; p[0] = 'H'; A: 文字列定数は、(ようするに)配列の初期化指定子として使われるとき を除いては、必ずしも変更可能ではない。以下の方法を試すこと。 char a[] = "hello, world!"; 質問1.32も参照のこと。 References: ANSI Sec. 3.1.4; ISO Sec. 6.1.4; H&S Sec. 2.7.4 pp. 31-2. 16.8: 「セグメンテーション違反(Segmentation violation)」とか「バスエ ラー(Bus error)」は何を意味するのか。 A: これらの症状は一般に、アクセスすべきでない記憶領域にプログラム がアクセスしようとしたことを意味している。きっとスタックが壊れ たかポインタの使い方が適切でなかったからに違いない。考えられる 原因としては以下のものが考えられる。 ローカル("自動の"、スタックに割り付けられる)変数のオーバーフロー、 ヌルポインタの誤った使い方(質問5.2, 5.20も参照)。初期化されて いないポインタ/境界の合ってないポインタ/その他適切でない割り付 けのされかたのポインタ(質問7.1と7.2参照)。mallocした領域が壊れ た(質問7.19参照)。関数引数の不一致、特にポインタが絡んだ場合、 2つ考えられるのはscanf()(質問12.12参照)とfprintf()(最初のFILE *の引数を渡されていることを確認すること)。 質問16.3と16.4も参照のこと。 17章 スタイル 17.1: Cのコードの書き方で最良のものは。 A: K&Rである。しばしば真似られる良い例を載せているだけでなく、避 けるべき悪い例には、立派な理由も載せている。 括弧の位置はたいして重要ではない。ただし人は括弧の位置 に強い信念を持っている。我々は世にあるいくつかの例から 選んだだけである。自分に向いている書き方を取り入れて、 首尾一貫して使い続けること。 大事なのはコードの配置が"完全な"ことよりも、選んだコードの配置 を首尾一貫して使うことである(それ自身、回りのコードと、あるい は共通部と)。もし君がコーディングを行うときの環境が(たとえば職 場の習慣や会社の方針)コーディングスタイルを示していなくて、自 分自身の書き方を作り出す気もないのなら、単にK&Rをまねればよい。 (さまざまな字下げや括弧の位置の持つ利点と欠点に関する調査は、 徹底的かつ細かく行うことができる。しかしここでは議論を繰り返さ ない。Indian Hillスタイルガイドを参照のこと)。 定義しにくい"よいスタイル"が持つ特質には、コードの配置の詳細以 上のものがある。もっと大事なコードの質の問題を抜きにして体裁を 整えるのに時間を割かないこと。 質問10.6も参照のこと。 References: K&R1 Sec. 1.2 p. 10; K&R2 Sec. 1.2 p. 10. 17.3: ほら、このわざを見て。 if(!strcmp(s1, s2)) これはよい書き方? A: とくによい書き方ということはない。ただし人気のある書き方ではあ る。このテストは、二つの文字列が同じときに成功する。しかし「!」 ("...でない")を使っていることで等しくないことをテストしている ように思える。 より優れた選択肢としては以下のようなマクロを使うことがある。 #define Streq(s1, s2) (strcmp((s1), (s2)) == 0) コーディングスタイルに関する考え方は、宗教に関する考え方と同じ で、議論に終りがない。よい書き方は価値ある目標であるし、たいて いは見ればよいか悪いかわかるが、文章にすることはできない。質問 17.10も参照のこと。 17.4: どうしてif(x == 0)と書く代わりに、if(0 == x)と書く人がいるのか。 A: これはよく以下のように書いてしまうことを防ぐためのコツである。 if(x = 0) 定数を==の前に持ってくる習慣を付けておけば誤って、 if(0 = x) と打ち込むとコンパイラが文句を付ける どうやら2回=を打ち込むことを覚えるよりは、テストのオペランドの 順をひっくり返すことを覚えることのほうがやさしい。 (訳注:本のほうには、これは特によい書き方というわけではないと書 いてある。実際これでは両辺が変数の場合のif(a = b)という誤りを 捉えることはできない。こんな技を覚える暇があれば、lintの使い方 を覚えること。) References: H&S Sec. 7.6.5 pp. 209-10. 17.5: printf()を呼び出しているところすべてに、いちいち(void)のキャス トを付けているコードを見かけた。なぜこんなことをするのか。 A: printf()は値を返す。ただしprintf()の戻り値をわざわざ確かめるプ ログラムは数少ない。コンパイラによっては(lintも)戻り値を読まず に捨てると警告を出すので、(void)に明示的にキャストすることは 「はい、この呼び出しの戻り値を無視することにしました。でも引き 続きその他の関数で戻り値を(うっかり)無視したら注意してください。」 というコンパイラへの依頼の表現である。strcpy()やstrcat()の呼び 出しにもvoidのキャストはよく行われる。これらの戻り値が、とんで もない値になることはないから。 References: K&R2 Sec. A6.7 p. 199; Rationale Sec. 3.3.4; H&S Sec. 6.2.9 p. 172, Sec. 7.13 pp. 229-30. 17.8: 「ハンガリー記法(Hungarian Notation)」とは。使う価値があるか。 A: ハンガリー記法は名前の付けかたの取り決めで、Charles Simonyiが 発明した。これは変数の型を(おそらく、その使い道も)変数の名前 に符号化する。一部のグループでは愛され、その他の人達からは容赦 なく酷評されている。主な利点は、データ型や意図する使い方が名前 を見ればわかるということである。主な欠点は、データ型は変数の名 前に付けて運んでまわるような大事な情報では必ずしもないことであ る。 References: Simonyi and Heller, "The Hungarian Revolution" . 17.9: Indian Hillスタイルガイドやそのほかのコーディング規約をどこか ら手に入れることができるのか。 A: さまざまな資料がanonymous ftpにより入手可能である。 場所 ファイルあるいはディレクトリ cs.washington.edu pub/cstyle.tar.Z (インディアンヒルガイドの改訂版) ftp.cs.toronto.edu doc/programming (Henry Spencerの 「Cプログラマの十戎」も含む) ftp.cs.umd.edu pub/style-guide 『プログラム書法』、『Plum Hall Programming Guidelines』、『C Style: Standards and Guidelines』のような本も参考にしたほうが いいかもしれない。参考文献参照のこと。(『C Style: Standards and Guidelines』は実際はスタイルガイドではない。これはスタイル ガイドを選んだり作り上げる際の指針を集めたものである。) 質問18.9も参照のこと。 17.10: gotoは悪で絶対に使ってはならないという人がいる。ちょっとこれは 行き過ぎではないか。 A: プログラミングの作法は文章作法と同じで、ちょっとした技能であっ てガチガチの規則で明文化することはできない。ただし書き方につい ての議論はもっぱらそういう規則を中心に回るようである。 goto文については、gotoを好き勝手に使うとすぐにスパゲッティのよ うにもつれた保守不能なコードになると昔からいわれている。しかし、 石頭にgoto文を使うことを禁止してもすぐに美しいプログラミングに 結び付くとは限らない。体系立てて考えないプログラマならgoto文を まったく使わなくても同じように複雑怪奇にもつれたコードを書いて しまう(たぶん代わりに妙に入れ子になったループやブール値の制御 変数を使って)。 プログラムの書き方に関するたいていの意見や"規則"は規則としてよ りは指針として考えたほうがうまくいく。プログラマが、この指針 で何を成し遂げたいのか理解すればもっとうまくいく。ある種の構文 を無闇に敬遠したり、理解することなく規則に従うことは、規則を使 えば避けられることになっているのと同じくらい多くの問題を引き起 こす可能性がある。 さらに、プログラムの書き方に関する見解は所詮見解にすぎない。" 書き方論争(style wars)"に引きずり込まれても、たいてい何も産み 出さない。一部の論点(質問9.2, 5.3, 5.9, 10.7で挙げたような)に ついてはお互い相手の意見を認めたり、意見が違うことを認めたり、 議論を打ち切ったりすることはないように見える。 18章 道具と資源 18.1: こんなのを捜している。 A: 以下の名前を持つプログラムを捜すこと (質問18.16も参照のこと)。 相互参照を生成するツール cflow または cxref, calls, cscope, xscope, ixfw 整形ツール/プリティプリンタ cb または indent, GNU indent, vgrind 改訂履歴管理、構成管理ツール RCS または SCCS Cソースを解読不能にするツール、 obfus または shroud, opqcp (シュレッダー) makeコマンドの依存関係を makedepend, あるいはcc -Mまたは 作り出すツール cpp -M コードのメトリックスを求める ccount, Metre, lcount, または ツール csize, もしくは URL http://www.qucis.queensu.ca:1999/Software- Engineering/Cmetrics.htmlを参照 McCabe and Associatesが販売している 製品もある。 行数測定ツール 大まかでよければUnixに標準で付いてくる wcで、またgrep -c ";"を使えばもう少し正確な 結果が得られる。 Cの宣言の補助ツール 質問1.21参照 (cdecl) プロトタイプ生成ツール 質問11.31参照 mallocの問題を追跡するツール 質問18.2参照 "選択的"プリプロセッサ 質問10.18参照 他のプログラム言語からの 質問11.31と20.26参照 変換ツール Cプログラム検定器(lint) 質問18.7参照 Cコンパイラそのもの 質問18.3参照 (上のツールの一覧表は完璧を求めたものではない。上の表に載って いないツールを知っていれば、この表の管理者に連絡を取って欲しい。) 別の編者によるツールの一覧表、各ツールに関する議論がUsenetのニュー スグループcomp.compilersやcomp.software-engに投稿されている。 質問18.16と18.3も参照のこと。 18.2: malloc()の厄介な問題はどうやって追跡すればよいか。 A: malloc()にまつわる問題の追跡を支援するデバッグ用パッケージは数 多くある。人気があるのはConor P. Cahill作の"dbmalloc"、これは comp.sources.miscに1992年に投稿された。volume 32に入っている。 その外には"leak"というのがcomp.sources.unixのvolume 27アーカイ ブから入手可能である。JMalloc.cとJMalloc.hは"Snippets"所蔵であ る。MEMDEBUGはftp.crpht.luのpub/sources/memdebugにある。質問 18.16も参照のこと。 商品版のデバッグ用ツールも多数存在する。これらはmalloc()に関係 した問題や、その他のなかなか解けない問題を追い詰めるのに非常に 役にたつ。 Nu-Mega Technologies社のBounds-Checker for DOS, P.O. Box 7780, Nashua, NH 03060-7780, USA, 603-889-2386. Centerline Software社の(かってはSaberという社名だった) CodeCenter(以前はSaber-Cという名前だった), 10 Fawcett Street, Cambridge, MA 02138-1110, USA, 617-498-3000. ParaSoft Corporation社のInsight, 2500 E. Foothill Blvd., Pasadena, CA 91107, USA, 818-792-9941, insight@parasoft.com . Pure Software社のPurify, 1309 S. Mary Ave., Sunnyvale, CA 94087, USA, 800-224-7873, info-home@pure.com . PLATINUM Technology社のFinal Exam Memory Advisor (以前 はAIB Software社のSentinelという名前だった), 1815 South Meyers Rd., Oakbrook Terrace, IL 60181, USA, 630-620-5000, 800-442-6861, info@platinum.com, www.platinum.com . AIB Software社のSENTINEL, 46030 Manekin Plaza, Dulles, VA 20166, USA, 703-430-9247, 800-296-3000, info@aib.com . The Kernel Group社のZeroFault 1250 Capital of Texas Highway South, Building Three, Suite 601, Austin, TX 78746, 512-433-3333, http://www.tkg.com, zf@tkg.com . 18.3: フリーまたは安く手に入るCコンパイラにはどのようなものがあるか。 A: 人気があって高品質なコンパイラとしてはFSFのGNU Cコンパイラすな わちgccが挙げられる。これはprep.ai.mit.eduのディレクトリ pub/gnuもしくは幾つか存在するFSFのアーカイブサイトから入手可能 である。MS-DOSへの移植であるdjgppもある。これはftp.delorie.com のpub/djgppから入手可能である。Simtelのミラーサイト(例: ftp.simtel.netのpub/simtelnet/gnu/djgppやftp.coast.netの SimTel/vendors/djgpp)からも入手可能である。 PCCというシェアウエアのコンパイラがある。PCC12C.ZIPという名 前で入手可能である。 Mix SoftwareのPower Cは非常に安価なMS-DOS用のコンパイラである。 連絡先は、1132 Commerce Drive, Richardson, TX 75801, USA, 214-783-6001. 最近開発されたコンパイラとしてはその他にlccがある。これは ftp.cs.princeton.eduのpub/lccからanother ftpで入手可能である。 MS-DOS用のシェアウエアのCコンパイラがftp.hitech.com.auの /hitech/pacificから入手可能である。非商用ならレジストレーショ ンしなくてもよい。 comp.compilersに関連したアーカイブは入手可能な(多くのプログラ ム言語の)コンパイラ、インタープリター、文法等についての大量の 情報を収集している。John R Levineが管理する(FAQリストも含む) comp.compilersのアーカイブはiecc.comにある。入手可能なコンパイ ラと関連する資源の一覧でMark Hopkins, Steven Robenalt, David Muir Sharnoffが保守しているものが、ftp.idiom.comの pub/compilers-list/から入手可能である。(rtfm.mit.eduや ftp.uu.netにあるnews.answersのアーカイブのcomp.compilersのディ レクトリも参照のこと。質問20.40参照。) 質問18.16も参照のこと。 18.4: プログラムを打ち込んだところだけれど、このプログラムは奇妙な動 きをする。どこか変なところがあるか。 A: まずはlintを(-a、-c、-h、-p や他のオプションをつけて)動かして みること。多くのCコンパイラは、実際にはコンパイラの仕事の半分 しかしていない。つまりソースコードの問題点の診断を、コードの生 成の邪魔にならない限りしないことになっている。 質問16.5, 16.7, 16.8を参照のこと。 References: Ian Darwin, _Checking C Programs with lint_ . 18.5: mallocを呼ぶたびにlintが出す「警告:ポインタの整合に問題の可 能性あり(warning:possible pointer alignment problem)」という メッセージを消す方法はあるか。 A: 問題は古いlintが、mallocが「どんな型のオブジェクトもうまく収ま るように整合した領域へのポインタを返す」ということを知らないし、 教える手段もないということである。#ifdef lintのなかでmalloc() の定義まがいを#defineしてこのメッセージを消すことは可能である が、そんなことをすれば本当に間違った使用法に対しても大事なメッ セージが出なくなってしまう。grep -vを使って勝手に無視するほう がやさしい。(lintのメッセージをあまり多く無視する習慣を付けな いこと。さもないと、ある日大事なメッセージを見落とすことになる。) 18.7: ANSI互換のlintはどこで手に入るか。 A: PC-LintとFlexlintという製品が(シュレッダーにかけたようなソー スで提供される。これはたいていのシステムでコンパイル可能である)、 Gimpel Software 3207 Hogarth Lane Collegeville, PA 19426 USA (+1) 610 584 4261 gimpel@netaxs.com から入手可能である。SVR4のlintはANSI互換で、UNIX Support Labs あるいは SYSTEM Vの再販業者から(他のC言語ツールと共に)購入可能 である。 もう一つのANSI互換のlintとしてはLCLintがある(上流工程の形式的 仕様の検査も可能である)。これは larch.lcs.mit.edu://pub/Larch/lclint/からanother ftp可能である。 lintがなくても、最近のコンパイラは、よくできたlintと同じくらい の多くの種類の診断をしようとする。(gcc -Wall -pedanticを進める 人が多い。) 18.8: ANSIの関数プロトタイプが用意されたことでlintは時代遅れになった のか。 A: まさか。まずプロトタイプは実際に存在して、しかも正しいときに だけ目的通りに機能する。うっかり間違ったプロトタイプは有害無益 だ。次にlintは複数のソースファイルに渡って一貫性を検査するし、 関数だけでなくデータの宣言も検査する。lintのように独立したプロ グラムになっていると、特定の実装に依存した余計な機能や余計な拡 張のついたコンパイラよりも、互換性が高く移植性の高いコーディン グの習慣を強制することにに気を配っているだろう。 ファイルをまたがった一貫性の検査をするのにlintの代わりに、どう しても関数プロトタイプを使いたいならば、ヘッダファイルでプロト タイプを正しく設定していることを確かめること。質問1.7と10.6を 参照のこと。 18.9: Cの独習書やその他の知的資源をインターネットで入手することはできるか。 A: いくつか存在する。 Christopher Sawtellの『Cプログラマへの覚え書き:Notes for C programmers』svr-ftp.eng.cam.ac.ukのmisc/sawtell_C.sharや garbo.uwasa.fiの/pc/c-lang/c-lesson.zipから入手可能である。 Tim Loveの『C for Programmers』svr-ftp.eng.cam.ac.ukのmiscディ レクトリから入手可。HTML版は http://club.eng.cam.ac.uk/help/tpl/languages/C/teaching_C/teaching_C.html にある。 Coronado EnterprisesのC入門はSimtelのミラーサイトの pub/msdos/c/にある。 Rick Roweの書いた独習書はftp.netcom.comの pub/rowe/tutorde.zipやftp.wustl.edu asの pub/MSDOS_UPLOADS/programming/c_language/ctutorde.zipから入手 可能である。 どうやらWebを使ったチュートリアルが http://www.strath.ac.uk/CC/Courses/CCourse/CCourse.htmlにある ようだ。 Martin BrownはC course materialをhttp://www- isis.ecs.soton.ac.uk/computing/c/Welcome.htmlで提供している。 Unixマシンの中には、シェルのプロンプトから「learn c」 と打ち込むとチュートリアルが始まるものもある。 最後に、本FAQの原著者はC言語のクラスを教えており、その講義ノートを ウエブで公開し始めた。これは http://www.eskimo.com/~scs/cclass/cclass.html から入手可能である。 [声明(Disclaimer): これらのチュートリアルを吟味したわけではな い。これらの中の少なくとも一つには多数の間違いがあると聞いてい る。また、この種の情報は急速に時代遅れになる。上に挙げたアドレ スは、このFAQを読んで試すころには、無効になっているかもしれな い。 これらのチュートリアルのいくつかと、Cに関する大量の情報が、 http://www.lysator.liu.se/c/index.htmlからWEBを通してアクセス 可能である。 Vinit CarpenterがCやC++を学ぶ際に使用可能な資源の一覧を管理し ている。これはcomp.lang.cやcomp.lang.c++に投稿され、このFAQが アーカイブされているのと同じサイトにアーカイブされている(質問 20.40参照)。http://vinny.csd.mu.edu/でWebを使って閲覧可能であ る。 以下の質問18.10も参照のこと。 18.10: C言語を学ぶのによい本は? A: Cに関する本は多すぎて、ここで名前を全部挙げることは不可能であ る。全部評価することも無理である。多くの人が最初の参考書が最上 のものであったと信じている。KernighanとRitchieによる『Cプログ ラミング言語』("K&R"今は第二版)のことである。プログラミングの 最初の教科書としてK&Rが向いているかどうかは意見が分かれる。実 際多くの人がK&Rを使って学んだし、しっかりと身に付けた。しかし ながらプログミング一般の基礎知識があまりない人の最初の教科書と してはちょっと冷たく客観的であると感じる人もいる。注釈と正誤表 がいくつかネットから入手可能である。 http://www.csd.uwo.ca/~jamie/.Refs/.Footnotes/C-annotes.htmlまたは http://www.eskimo.com/~scs/cclass/cclass.htmlや http://www.lysator.liu.se/c/c-errata.html#main 。 素晴らしい参照用マニュアルとしてはSamuel P. HarbisonとGuy L. Steeleによる『新・詳説C言語H&Sリファレンス H&Sリファレンス (C: A Reference Manual)』がある。これは第四版まで出ている(訳注: 日本語訳は3版に対応したものまで出ている)。 一からCを学ぶのには向いていないが、このFAQは書籍の形態で出版さ れている。参考文献を参照のこと。 Mitch WrightがCとUnixの注釈付きの文献一覧を管理している。これ はftp.rahul.net のディレクトリpub/mitch/YABLからanonymous ftp が可能である。 The Association of C and C++ Users (ACCU)がCとC++の教科書の comprehensiveなbibliographic reviewsをmaintainしている。 場所はhttp://bach.cis.temple.edu/accu/bookcaseと http://www.accu.org/accu 。 FAQリストの編者は、この質問のこれまでの回答を集めたものを持っ ている。希望があれば送る。上の質問18.9も参照のこと。 18.13: 標準のCライブラリのソースはどこにあるのか。 A: 1つは(パブリックドメインではないけれど)、P.J. Plaugerの『標準C ライブラリ(The Standard C Library)』にある(参考文献参照)。Cラ イブラリの全体または一部はNetBSDやGNUプロジェクト(Linuxプロジェ クトも含む)の一部として書かれ容易に入手可能である。質問18.16を 参照のこと。 18.14: 式を構文解析して、式の演算結果を得るコードが欲しい。 A: 2つのパッケージが入手可能である。1つ目は「defunc」というパッ ケージ。comp.source.miscに1993年12月(V41 i32,33)に、また alt.sourcesに1994年1月にポストされ、sunsite.unc.eduのディレク トリpub/packages/development/libraries/defunc-1.3.tar.Zから入 手可能である。もう1つは「parse」でlamont.ldgo.columbia.eduか ら入手可能である。その他の選択肢としてはS言語のインタープリター がある。これはamy.tch.harvard.eduのpub/slangからanonymous ftp で入手可能である。またシェアウエアーのCmm(C-minus-minusまたはC から難しいところをマイナスしたもの)もある。質問18.16も参照のこ と。 構文解析/式の評価のコードは『Software Solutions in C』にも載っ ている(12章, pp. 235-55)。 18.15: C言語の文法をBNFやYACCで書いたものは、どこで手に入るか。 A: 最も確かな文法は当然ANSI規格の中にある。質問11.2を参照のこと。 その他にJim Roskindによるものがics.uci.eduのディレクトリ pub/*grammar*に置かれている。ANSI文法に肉付けして動くようにし たものが(Jeff Leeによる) uunet(Q17.12を参照)の usenet/net.sources/ansi.c.grammar.Zに、対応する字句解析ツール とともに置かれている。FSFのGNU Cコンパイラは文法を含んでいる。 K&Rの第2版の付録にも付いている。 comp.compilersのアーカイブは文法についてもっとたくさんの情報を 保存している。質問18.3を参照のこと。 References: K&R1 Sec. A18 pp. 214-219; K&R2 Sec. A13 pp. 234- 239; ANSI Sec. A.2; ISO Sec. B.2; H&S pp. 423-435 Appendix B. 18.15a: Cコンパイラの妥当性を検査する一連のテストをだれか持っていない か。 A: Plum Hall(以前はCardiff, NJ、現在はHawaii)が売っている。other その他のパッケージとしてはRonald GuilmetteのRoadTest(tm) Compiler Test Suites (ftp to netcom.com, pub/rfg/roadtest/announce.txt for information)やNullstoneのAutomated Compiler Performance Analysis Tool (http://www.nullstone.com参照)がある。FSFの GNU C(gcc)の配布にはc-torture-test.tar.Zというパッケージが含ま れている。これはコンパイラのよくある問題点をチェックするもので ある。Kahanのパラノイア・テストはnetlib.att.comのディレクト リnetlib/paranoiaから手に入れることができる。これはCの浮動小数 点計算の実装に厳しいテストを行う。 18.15c: 有用なコードの断片やコード例を集めたものはどこから入手可能か。 A: Bob Stoutの"SNIPPETS"コレクションはftp.brokersys.comのディレク トリpub/snippetsかウエブでhttp://www.brokersys.com/snippets/か ら入手可能である。 Lars Wirzeniusの"publib"ライブラリがftp.funet.fiの pub/languages/C/Publib/から入手可能である。 質問14.12, 18.9, 18.13, 18.16も参照のこと。 18.16: どこから、これらのパブリックドメインのプログラムを手に入れるこ とができるのか。 A: 入手可能なプログラムの数や、おおっぴらにアクセス可能なアーカイ ブサイトの数や、サイトにアクセスしようとする人の数が増えるにつ れ、この質問への解答はやさしくなる一方で難しくもなっている。 社会の役に立つことを目的とした大きなアーカイブサイトがたくさん ある。たとえばftp.uu.netとかarchive.umich.edu、oak.oakland.edu、 sumex-aim.stanford.edu、wuarchive.wustl.eduなどである。これら のサイトには莫大な量のソフトウエアやその他の情報を保存していて、 すべて自由に入手可能である。FSFのGNUプロジェクトの中心となる配 布のサイトはprep.ai.mit.eduである。これらの有名なサイトは概し て混んでいてつながりにくい。そこで"ミラー(mirror)"サイトがたく さんあって負荷の分散に努めている。 インターネットにアクセスできる人には、アーカイブサイトからファ イルを取り出す昔からの方法はanonymous ftpである。ftpが使えない 人には、メールによるftpのサービスを行っているサーバーがいくつ かある。ますますワールドワイドウエブ(WWW)が配布の公表や索引だ けでなく大きなデータファイルの転送にまで使われるようになってき ている。きっともっと新しいアクセス方法が発表されていることだろ う。 ここまでは答えやすい部分である。難しいのは詳細である。このこの 記事はプログラムを保存しているサイトのすべてや、サイトにアクセ スする方法を突き止めたり、挙げることはできない。そもそもネット にアクセスできるなら、動いているサイトや便利なアクセス方法につ いての、このFAQに載ってるのより最新の情報にアクセスすることが できる。 この質問のその他のやさしそうで本当は難しい面は当然どうやってど のサイトが探しているものを保存しているかを見つけることである。 この分野には途方もない労力がつぎ込まれていて、毎日のように新し い索引つけのサービスが現れている。こういうサービスの最初のもの の一つが「アーチー(archie)」である。ネット上で入手可能なプログ ラムや資源で名前が分かっているものなら、アーチーサーバーがどの anonymous ftpサーバーにあるかたいてい教えてくれる。アーチーの コマンドが手元のシステムに載ってるかもしれないし、なかったとし たら「help」と本文に書いてarchie@archie.cs.mcgill.caへメールを 送ればいい。 Usenetへアクセスできるのなら、comp.sources.unixや comp.sources.miscといったグループへの定期的なポストを参照する こと。そこには保存の方針や取り出しかたが記述してある。これらの グループに投稿されたものは ftp://gatekeeper.dec.com/pub/usenet/comp.sources.unix/や ftp://ftp.uu.net/usenet/comp.sources.unix/といったところにアー カイブされている。ニュースグループcomp.archivesの記事には様々 な情報の、anonymous ftpによる入手方法の紹介が含まれている。最 後にcomp.souces.wantedが、たいていはソースのありかをたずねるの に最もふさわしいニュースグループである。その場合でもポストする 前にFAQのリストである「How to find sources(どうやってソースを 見つかればよいか)」をチェックすること。 質問14.12も参照のこと。 19章 システム依存 19.1: Returnキーが押されることを待つことなしにキーボードから1文字読 むのはどうすればいいのか。入力を受け付けてる間、文字が画面に エコーされないようにするにはどうすればいいのか。 A: やれやれ、Cには上のようなことを行う標準的な方法も移植性の 高い方法もない。画面とかキーボードとはどういうものを指すのかさ え規格の中では出てこない。規格は簡単な、文字の入出力ストリームし か扱っていない。 どこかの層で、キーボードからの入力は通常いったん集められ一度に 1行ずつ、入力を要求しているプログラムに渡される。これによって オペレーティングシステムが入力行の編集機能(バックスペース/デリー ト/ruboutなど)を一貫した方法で、しかもプログラムごとに組み込む 必要なく用意するすることが可能となる。ユーザーが納得して改行キー (あるいは類似のキー)を叩いて初めて入力行は呼び出した側のプログ ラムから使えるようになる。プログラムが一度に一文字(getchar()の ようなルーチンを使って)入力を読んでいるように見えても、最初の 呼び出しはユーザーが行全体を入力するまでブロックされる。行全体 が読み込まれた時点では、多くの文字が利用可能になり、矢継ぎ早の 文字の取り出し要求も(例:getchar()の呼び出し)満たされる。 プログラムに文字が到着するとすぐに読ませたいなら、処理の流れは 入力ストリームのどこで入力を1行分集めているかと、1行分集めるの をやめるにはどうすればよいかに依存する。システムによっては(例: MS-DOS, あるモードでのVMS)、プログラムは異なった、または修正さ れたOSレベルの入力コールの一組を使うことで、一度に1行分丸々処 理することを迂回することができる。その他のシステムでは(例:Unix、 別のモードでのVMS)、オペレーティングシステムのシリアル入力を担 当している部分("ターミナルドライバー"と呼ばれることが多い)を、 一度に一行分丸々は処理しないモードに移す。移った後は、通常の入 力ルーチン(例:read(), getchar()など)は文字を即座に返す。いくつ かのシステムでは(特に古い、バッチ処理中心の汎用機では)入力の処 理は周辺のプロセッサで行われ、一度に一行丸々処理させるかどう かしか命令することはできない。 よって、一度に1文字を入力することが必要なら(あるいはキーボー ドからの入力時の画面へのエコーをとめる必要があるなら。これは類 似の問題である)、使っているシステムに固有の技を使う必要がある。 comp.lang.cはCで手におえる話題が中心なので、上のような質問は comp.unix.questionsやcomp.os.msdos.programmerといった特定のシ ステムのニュースグループで聞くか、そういうグループのFAQを見る ほうが普通はよい解答が返って来る。システムが違っても解答は共通 であることが多いが、システム特有の質問に答えるときは、君のシス テムにあてはまる解答が他の人全部にあてはまる解答でないかもしれ ないことに注意すること。 しかしながら、これらの質問はあまりにも何度も聞かれるので、以下 によくある状況用の簡潔な解答をつける。 cursesの中には関数cbreak()を用意しているものもある。これが望み の機能を果たす物である。画面に表示することなくパスワードを読み たいというのであればgetpass()を試せばよい。Unixでは、ターミナ ルドライバーのモードをいじるのにioctlを使えばよい(「古典的な」 システムではCBREAKやRAW、SYSTEM VやPOSIX準拠のシステムでは ICANON、c_cc[VMIN]、c_cc[VTIME]、すべてのバージョンでECHO)。最 後の最後の方法としてはsystem()とsttyコマンドを使う。(もっと詳 しく知りたければ、古典的なバージョンではとtty(4)、 System Vではとtermio(4)、POSIXではと termios(4)を参照せよ。) MS-DOSでは、getch()やgetche()を使うか、 対応するBIOSの割り込みを使う。VMSでは、スクリーン管理機能 (SMGZ$)やcurses、一度に一文字欲しいのであれば低レベルの$QIOを IO$_READVBLKを(たぶんIO$M_NOECHOも必要だろう)付けて試すこと (VMSの端末ドライバーで一度に一文字、すなわち"素通し"モードを設 定することも可能である)。そのほかのシステムでは、自分でやるし かない。 (ちなみに、setbuf()やsetvbuf()を使って標準入出力をバッファしな いようにするだけでは一般には1度に1文字の入力を実現することが できないことに注意。) 移植性の高いプログラムを書くつもりなら、よい取り組みかたは(1) ターミナルドライバーや入力システムを(必要なら)一度に1文字ずつ のモードに移す関数、(2)文字を取得する関数、(3)関数の処理が終わっ たらターミナルドライバーを最初の状態に戻す関数の3つの関数を一 組にしたものを自分で定義ことである。(理想をいえば、このような関 数の集合は、いつかC規格の一部になるかもしれない。) このFAQの拡 張版には(質問20.40参照)、いくつかの普及しているシステム用の例 も載っている。 質問19.2も参照のこと。 References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1; POSIX Sec. 7. 19.2: 読み込むことができる文字が残っているかどうか(できるなら後いく つ残っているか)知ることができるか。できないとしたら、文字が入っ てこないときに処理が止まってしまわないような読み込みはどうやれ ばよいか。 A: これも、まったくオペレーティングシステムに依存した問題である。 cursesの中には、そのような目的のために関数nodelay()を用意して いるものもある。システムによっては、「ブロックしないI/O」や 「select」とか「poll」という名のシステムコール、FIONREAD ioctl、 c_cc[YTIME]、kbhit()、rdchk()、あるいはopen()やfcntl()の O_NDELAYオプションを用意しているかもしれない。質問19.1も参照の こと。 19.3: 処理の何%まで終了したかを表示して、それをその場で更新させるに はどうすればよいか。また仕事の進んでいることを"バトンを回す"こ とで知らせるのはどうやればよいのか。 A: こういう簡単なことであれば、結構移植性高く行うことができる。文 字'\r'を出力すると、普通は行送り(line feed)することなく復帰 (carriage return)する。それで現在行を上書きすることができる。 文字'\b'はバックスペースを表わし、普通はカーソルを左に1文字動 かす。 References: ANSI Sec. 2.2.2; ISO Sec. 5.2.2. 19.4: どうすれば画面に表示されている文字を一掃することができるか。 どうすれば反転文字で出力することができるか。 どうすればカーソルを、指定したx,y位置に動かすことができるか。 A: この手の話は、端末(や表示装置)の種類に左右される。こういう 処理にはtermcapやcursesのようなライブラリ、あるいはシステム 固有のルーチンを使わなければいけない。 画面をクリアするのに多少でも移植性の高い方法は、用紙送り (form-feed)文字('\f')を印字することである。この文字を印字する ことで表示されている内容がクリアされるものもある。もっと移植性 の高い方法は、今表示されているものが全部見えなくなるだけ改行を 印字することである。最後の手段として、system() (質問19.27参照) を使ってオペレーティングシステムが用意している画面クリアの命令 を呼び出すこともできる。 References: PCS Sec. 5.1.4 pp. 54-60, Sec. 5.1.5 pp. 60-62. 19.5: 矢印キーを読むにはどうしたらよいか。ファンクションキーは。 A: terminfoやいくつかのtermcapやいくつかのcursesは、こういうASCII コードにないキーに対応している。よくあるのは、特殊なキーは複数 の文字を連続して送り出す(普通はESC, '\033'で始まる)。こういう 文字の並びの構文解析は慎重を要するものになる可能性がある (cursesなら、最初にkeypad()を呼べば、構文解析までやってくれる)。 MS-DOSではキーボードからの入力を読んでいて値0('0'ではない)を持 つ文字を受け取ったら、それは次に読む文字は特別なキーを表わす符 号であることを意味している。どんなDOSのプログミングガイドでも いいからキーボードのコードを参照すること。(簡単に説明する。 上、左、右、下矢印キーはそれぞれ72、75、77、80である。ファンク ションキーは59から68に対応する。訳注: これはPC互換機の話である。 NECの98シリーズには当てはまらない) References: PCS Sec. 5.1.4 pp. 56-7. 19.6: どうすればマウスの出力を読むことができるか。 A: 対象とするシステムの資料を参照すること。あるいは適切なシステム 専門のニュースグループでたずねること(当然FAQを先に調べること)。 マウスの取り扱いは、X WindowとMS-DOSとMacintoshではまったく 異なる。たぶん他のシステムでも異なるだろう。 19.7: シリアル(COM)ポートを使ったI/Oはどうやればよいか。 A: それはシステム次第である。Unixではよく、/devにあるデバイスをオー プンしたり(open)、読んだり(read)、書き込んだり(write)する。ま たデバイス ドライバの機能を使って、I/Oの特性を調整する。(質問 19.1と19.2を参照。) MS-DOSでは、あらかじめ定義されたストリーム であるstdauxや、COM1のようなスペシャルファイルや、原始的なBIOS の割り込みや、(かなりの性能を要求するときは)世の中にたくさんあ る割り込み駆動のシリアルI/Oのパッケージを使う。ネットワーク上 で何人かがJoe Campbellの書いた『C Programmer's Guide to Serial Communications』を推薦している。 19.8: 出力先をどうすればプリンターに切り替えることができるか。 A: Unixではpopen()(質問19.30参照)を使ってlpやlprプログラムに書き 込むか、/dev/lpのようなスペシャルファイルをオープンする。 MS-DOSでは、(C規格の標準ではないが)あらかじめ定義された標準入 出力のストリームstdprnに書き込むか、スペシャルファイルである PRNやLPT1をオープンする。 References: PCS Sec. 5.3 pp. 72-74. 19.9: エスケープシーケンスを使って、端末やその他のデバイスを制御する のはどうすればいいのか。 A: そもそもデバイスに文字を送り込むのはどうやればいいかわかってい れば(上の質問19.8参照)、エスケープシーケンスを送り込むのは何で もない。ASCIIでは、ESCのコードは033(10進では27)なので、 fprintf(ofd, "\033[J"); のようなコードを書けばESC [ Jというシーケンスを送り出す。 19.10: グラフィックするのは。 A: 昔々、Unixにはデバイスに依存しない、plot(3)や plot(5)に記述された、小さくまとまった結構よくできた図示ルーチンが 存在した。しかし、ほとんど使われなくなってしまった。 MS-DOSでプログラムするときは、VESAやBGIに準拠したライブラリ を使ったほうがいいだろう。 プロッタの種類がはっきりしてるときは、絵を描かせることは適切な エスケープシーケンスを送る話になる。したがって質問19.9を参照の こと。プロッタのベンダーがCから呼べるライブラリを提供してるか もしれないし、インターネットから引っ張って来ることができるかも しれない。 特定のウインドウシステム(Macintosh、X Window、Microsoft Windows)用のプログラムには、そのシステムが持つ機能を使う。関 連する資料やニュースグループやFAQを参照のこと。 References: PCS Sec. 5.4 pp. 75-77. 19.11: ファイルが存在するかどうかはどうやって調べればよいか。指定され た出力ファイルがすでに存在するときにはユーザーに了解を取りたい。 A: この判定を信頼性が高く移植性も高く実行することは意外にも難しい。 どんなテストも、テストをしてからファイルを開こうとするまでの間 に(その他のプロセスによって)生成されたり削除されたりすれば、無 効になってしまう可能性がある。 解答として考えられる3つはstat()とaccess()とfopen()である。 (fopen()を使ってファイルの存在をざっとテストするには、ファイル を開いて即座に閉じればいい。)この3つの中でfopen()だけが広く移 植可能で、access()はもし存在しても、Unixのset-UID機能を使った プログラムでは注意深く使う必要がある。 ファイルを開くような作業がうまくいくか前もって予測しようとする より、開いてみて、戻り値を見て、失敗してたら文句をつけるほうが 良い考えである。(すぐわかるように、これでは、ファイルが存在す るときは上書きしたくないときには、ファイルを開くときにO_EXCLオ プションのようなものがないとうまくいかない。O_EXCLオプションは この場合やって欲しいことをぴったりやってくれる) References: PCS Sec. 12 pp. 189,213; POSIX Sec. 5.3.1, Sec. 5.6.2, Sec. 5.6.3. 19.12: どうすれば読む前にファイルの大きさを知ることができるか。 A: もしも"ファイルの大きさ"が、C言語を使ってファイルから読むこと のできる文字の数ということであれば、一般にはこの数を前もって知 ることは不可能である。 Unixでは関数stat()が正確な答えを与えてくれる。他のシステムの中 にもUnixのstat()に類似の関数を用意しているものがあって、そうい う場合は近似値を与えてくれる。fseek()を呼んでファイルの最後ま で進んで、ftell()を使えばよい。しかしこれもstat()が抱えている のと同じ問題を抱えている。fstat()は移植性が高くないし、たいて いstat()が返すのと同じ情報を返す。ftell()はバイナリーファイル を除いては正しくバイト数を返すとは限らない。filesize()とか filelength()というルーチンを用意しているシステムもある。これら のルーチンも移植性が高いわけではない。 本当にファイルのサイズを前もって決めておかなければならないのか。 Cプログラムから見えるファイルのサイズを決定する最も正確な方法 は、ファイルを開いて読むことであるから、ファイルを読みながらサ イズを知るように書き換えたほうがいい。 References: ANSI Sec. 4.9.9.4; ISO Sec. 7.9.9.4; H&S Sec. 15.5.1; PCS Sec. 12 p. 213; POSIX Sec. 5.6.2. 19.12a: ファイルがいつ変更されたかはどうすればわかるか。 A: UnixやPOSIXにはstat()というのがある。 これはその他の多くのシステムでも用意されている。 (質問19.12参照。) 19.13: まったく消し去ることや上書きすることなくファイルをその場で短く することはできるか。 A: BSDシステムはftruncate()を、他のものはchsize()を、またシステム によっては(ドキュメントには書かれていないだろうけれど)fcntlの オプションとしてF_FREESPを用意している。MS-DOSではwrite(fd, "", 0)が使えることがある。けれど頭のほうにあるブロックを削除す る、本当に移植性の高い解決策も方法も存在しない。質問19.14も参 照のこと。 19.14: ファイルの真ん中に1行(あるいは1レコード)挿入する、あるいは削除 するのはどうやればよいか。 A: ファイルを書き直すのでなければ、たぶん不可能だろう。普通は、単 純にファイルを書き直す。(レコードを削除する代わりに、削除したと 印を付けるだけにする手もある。こうすれば書き直しをしなくてもす む。) 質問12.30と19.13も参照のこと。 19.15: オープンしたファイルのファイル識別子からファイル名を復活するこ とができるか。 A: この問題は、たいてい解決不能である。たとえばUnixではディスク全 体を端から端まで調べることが(たぶん特別な許可が必要となるだろ うが)理屈の上では必要で、ファイル識別子がパイプや削除された後 のファイル(複数のリンクが張られているファイルに対しては誤解を まねくような答えを返すだろう)を指していたら、この方法もうまく いかない。オープンしたファイルの名前を(たぶんfopen()に関数を一 段かぶせて)自分で覚えておくのが一番よい。 19.16: どうやればファイルを削除することができるか。 A: 標準Cのライブラリ関数にremove()がある。(よってこれは、この章 の数少ない、解答が「システム依存」でない質問である。) 古い、 ANSI制定以前のUnixシステムにはremove()はないので、その場合は unlink()を試してみること。 References: K&R2 Sec. B1.1 p. 242; ANSI Sec. 4.9.4.1; ISO Sec. 7.9.4.1; H&S Sec. 15.15 p. 382; PCS Sec. 12 pp. 208,220- 221; POSIX Sec. 5.5.1, Sec. 8.2.4. 19.17: どうして明示的にパスを指定してファイルが開けないのか。 fopen("c:\newdir\file.dat", "r") だとうまくいかない。 A: ここで開こうとしているファイルは、つまりファイル名に\nや\fを含 んだファイルは、たぶん存在しないし、開こうとしてるつもりのファ イルでもない。 文字定数や文字列リテラルでは、バックスラッシュ\は拡張文字(エス ケープキャラクタ)であり、次に続く文字に特別な意味を与える。 バックスラッシュそのものをパス名の一部としてfopen()(その他のルー チンでも)に正しく渡すには、バックスラッシュを2回続けて書かなけ ればいけない。1つめのバックスラッシュは2つめのバックスラッシュ をエスケープする。 fopen("c:\\newdir\\file.dat", "r"); 別のやりかたとしては、MS-DOSでは、スラッシュ'/'もディレクトリ の分離文字に使えることがわかっている。そこで以下のように書くこ とができる。 fopen("c:/newdir/file.dat", "r"); (ところで、プリプロセッサの#include前処理指令で出てくるヘッ ダファイルの名前は文字列リテラルでないので、その中ではバック スラッシュのことは心配しなくてよい。) 19.18: 「ファイルを開きすぎ(Too many open files)」というエラーが出た。 同時に開けるファイルの数をどうすれば増やせるのか。 A: 同時に開くことのできるファイルの数には、実際には少なくとも2つ の資源の制限がある。下位の層の話である"ファイルディスクリプタ" や"ファイルハンドル"をオペレーティングシステムがいくつ持ってい るかと、標準入出力ライブラリの持つFILE構造体がいくつあるかであ る。両方とも十分な数でなければならない。MS-DOSでは、オペレーティ ングシステムのファイルハンドルの数をCONFIG.SYSに1行記述するこ とで制御することができる。コンパイラの中には標準入出力のFILE構 造体の数を増やす命令(たぶんソースにも追加が必要)を持っているも のもある。 19.20: ディレクトリの内容を読むにはどうすればよいか。 A: opendir()やreaddir()が使えるかどうか調べること。これらのルーチ ンはPOSIXの一部で、たいていのUnixシステムに載っている。MS-DOS、 VMS、その他のシステム用の実装も存在する(MS-DOSには実質的に同じ 仕事をするFINDFIRST、FINDNEXTというルーチンも存在する)。 readdir()はファイルの名前しか返さない。ファイルについてもっと 情報が必要であれば、stat()を呼ぶ。ファイル名がワイルドカードと 一致するかどうかについては、質問13.7を参照のこと。 19.22: どれだけメモリが使えるかはどうやればわかるか。 A: オペレーティングシステムが、そういう情報を返すルーチンを用意し てるかもしれない。ただし、これはまったくシステム依存の話だ。 19.23: どうやれば64Kより大きな配列や構造体を割り付けることができるのか。 A: まっとうなコンピューターなら使用可能なすべてのメモリに、こっ ちが意識しないでアクセスできるのが当たり前である。運悪くまっと うでないコンピューターの相手をすることになったら、プログラム内 のメモリの使いかたを考え直すか、さまざまなシステム依存の技を 使うかする必要がある。 64Kというのは(それでも)けっこう大きなメモリの塊である。どんな にたくさんメモリがコンピューターに載っていても、大量のメモリを 連続に切れ目なく割り付けようとするのは欲張りすぎである。(C規格 は、1つのオブジェクトが32Kより大きくなることを保証していない。) メモリ全体に切れ目がないことを必要としないようなデータ構造を使 うようにするほうが、良い考えであることが多い。動的に割り付けた 多次元の配列には、質問6.16のところで紹介したように、ポインタへ のポインタが使える。構造体の大きな配列を使う代わりに、線形リス トや構造体へのポインタの配列を使えばよい。 (8086ベースの)PC互換システムを使っていて640Kの壁にぶつかったら、 "ヒュージ(huge)"メモリモデルを使うか、拡張メモリ(訳注:日本語で はexpanded memoryとextende memoryを区別する用語がない)を使うか、 halloc()やfarmalloc()のようなmallocの変形を使うか、セグメント を意識させない32ビットの"平らな(flat)"コンパイラ(例: djgpp、質 問18.3参照)を使うか、何かしらのDOSエクステンダーを使うか、オペ レーティングシステムを取り替える。 References: ANSI Sec. 2.2.4.1; ISO Sec. 5.2.4.1. 19.24: 「DGROUPデータの割り付けが64Kを越えた(DGROUP data allocation exceeds 64K)」というエラーメッセージは何を表わしているのか。ど うすればよいのか。ラージモデルを使えば64K以上のデータが使える ものだと思っていた。 A: ラージモデルを使ってもMS-DOSのコンパイラは、ある種のデータ(文 字列、初期値付きのグローバル変数やスタティック変数の一部)をデ フォルトのデータセグメントに押し込む。そしてこのセグメントがあふ れる。グローバル変数の数を減らすか、すでにまあまあの量まで抑え ていたら(あるいは問題が文字列の数か何かなら)、コンパイラにデフォ ルトのデータセグメントをそんなにたくさん使わないようにさせるこ とができるかもしれない。"小さな"データオブジェクトだけをデフォ ルトのデータセグメントに置き、"小ささ"のしきい値を設定する手段 (たとえばマイクロソフト社のコンパイラでは/Gtオプション)を提供 しているコンパイラもある。 19.25: あるアドレスに位置するメモリ(メモリマップされたデバイス、 あるいはグラフィックメモリ)にどうやってアクセスすればよいか。 A: 適切なデータ型のポインタを、望むアドレスの値に設定する。 (明示的にキャストをして、コンパイラにこちらが移植性のない変換 をする気があることを伝える) unsigned int *magicloc = (unsigned int *)0x12345678; そうすれば*magiclocは望む場所を指す。(MS-DOSでは、セグメントと オフセットの相手をするのにMK_FP()のようなマクロが便利かもしれ ない。) References: K&R1 Sec. A14.4 p. 210; K&R2 Sec. A6.6 p. 199; ANSI Sec. 3.3.4; ISO Sec. 6.3.4; Rationale Sec. 3.3.4; H&S Sec. 6.2.7 pp. 171-2. 19.27: Cプログラムの中から別のコマンド(単体の実行可能プログラム、オペ レーティングシステムのコマンド)を起動したい。どうすればよいか。 A: ライブラリ関数であるsystem()を使う。これはまさしく上記を実行す る。system()の戻り値は、良くてコマンドのexitのステータスで、コ マンドの出力とは普通はぜんぜん関係ない。system()は起動すべきコ マンドを表わす文字列を1つだけ引数として取る。複雑なコマンド行 を組み立てる必要があればsprintf()を使う。質問19.30を参照のこと。 References: K&R II Sec. B6 p. 253; ANSI Sec. 4.10.4.5; H&S Sec. 21.2; PCS Sec. 11 p. 179; 19.30: 別のプログラムやコマンドを実行して、その出力を捕まえるのはどう すればよいのか。 A: Unixや他のいくつかのシステムはpopen()ルーチンを用意している。 このルーチンはコマンドを走らせているプロセスにつなげたパイプへ の標準入出力のストリームを、出力を読み取れる(あるいは入力を用 意する)ように設定するものである。 popen()が使えない環境なら、system()を使って、出力をファイルに 書き出し、後からファイルを開いて中身を読むことができるかもしれ ない。 Unixを使っていてpopen()では不足なら、pipe(), dup(), fork(), exec()といった関数を調べること。 (ところで、ひとつだけおそらく絶対うまくいかないのは、freopen() をつかうことである。) References: PCS Sec. 11 p. 169. 19.31: どうすればプログラムが起動されたときの絶対パスを知ることができ るか。 A: argv[0]に絶対パスやパスの一部が入っているかもしれないし、何も 入っていないかもしれない。argv[0]にパス名が入っているが完全で ないときは、シェルのようなコマンド行を解釈するソフトがコマンド を探す筋道を真似ればいい。しかしながら確実な方法は存在しない。 References: K&R1 Sec. 5.11 p. 111; K&R2 Sec. 5.10 p. 115; ANSI Sec. 2.1.2.2.1; ISO Sec. 5.1.2.2.1; H&S Sec. 20.1 p. 416. 19.32: 実行可能プログラムと同じディレクトリにあるプログラムの設定ファ イルがどこにあるかを自動的に捜したい。どうやればよいか。 A: これは難しい。上の質問19.31も参照のこと。使える方法を思い付い たとしてもプログラムの補助(ライブラリ用の)ディレクトリを、環 境変数かなにかを使って、変更可能にしたいと思うようになるかもし れない。(プログラムの設定ファイルを様々な場所に置けるようにし ておくのは、何人かでそのプログラムを使うときに、大事な話となる。 例:マルチユーザシステムで) 19.33: どうすればプロセスが、起動した側の環境変数を変更することができ るか。 A: 可能かもしれないし不可能かもしれない。それぞれのオペレーティン グシステムが、Unixに類似の変数名と値を結び付ける機能を、それぞ れの方法で実装している。"環境"が実行中のプログラムによって都合 よく変更できるかどうかと、できるとすればその方法は、システムに 依存する。 Unixのプロセスは自分の環境を変更することができる(setenv()や putenv()をこの目的のために用意しているシステムもある)。そして、 その環境はたいてい子プロセスに渡される。しかし親プロセスにまで 戻ることはない。 19.36: どうすればオブジェクトファイルを読み込んで、その中にあるルーチ ンに飛び込むことができるか。 A: ダイナミックリンカやダイナミックローダーが必要である。領域を割 り付けて、その領域にオブジェクトファイルを読み込むことはできる。 しかしオブジェクトファイルのフォーマットやその配置などについて、 かなりの知識が必要となる。BSDではsystem()とld -Aを使ってリンク させることができる。SunOSやSystem Vの多くのバージョンには-ldl というライブラリが載っていて、これを使えばオブジェクトファイル を動的にロードすることができる。VMSではLIB$FIND_IMAGE_SYMBOLを 使う。GNUのパッケージにdldというのが存在する。質問15.13も参照 のこと。 19.37: 1秒より細かい遅れや、ユーザの反応の1秒より細かい計測は、どう実 装すればよいか。 A: 残念ながら移植性の高い方法は存在しない。V7 Unixやそこから派生 したシステムは、かなり役に立つftime()を用意していた。この関数 はミリ秒単位の精度を持っていた。しかしSYSTEM VやPOSIXから消え てしまった。他に探すべき関数としてはclock()やdelay(), gettimeofday(), msleep(), nap(), napms(), setitimer(), sleep(), times(), usleep()がある(しかしながらwait()というルー チンは、少なくともUnixでは、望みのものではない)。select()や poll()は(もし手に入れば)、簡単な遅れを実装するのに使える。 MS-DOSマシンでは、システムタイマーやタイマーの割り込みをプログ ラムしなおすことで実現できる。 これらの関数の中でclock()だけがANSI規格の一部である。clock()を 2回呼んで、その差が経過時間を表わす。もしCLOCKS_PER_SECが1より 大きければ、差は秒以下の分解能を持つ。しかしながら、clock()が 返すのはclock()を呼び出したプログラムのプロセッサの使用時間で、 マルチタスクのシステムでは実際に経過した時間とぜんぜん違うかも しれない。 遅れを実装するのに使えるのが時間を報告する関数しかない場合でも、 CPUパワーを一点に集中し処理待ちの状態を作り出して遅れを実装す ることができる。けれどこれはシングルユーザーのシングルタスクの システムでだけ許される選択肢である。というのも、これは他のプロ セスにとってはまったく迷惑な話であるからである。マルチタスクの システムでは、指定した時間だけプロセスを眠らせる関数を使うこと。 たとえばsleep()やselect()やpause()を、alarm()やsetitimer()と共 に使う。 本当に短い遅れなら、なにも実行しないループを使いたい気がしてく る。 long int i; for(i = 0; i < 1000000; i++) ; けれど、どうやってでもこの誘惑を払いのけなければいけない。1つ には、注意深く計算したつもりの遅れを実現するループが、次の月に もっと速いプロセッサが登場してうまく動かなくなると相場が決まっ ているからである。もっと悪いことに、賢いコンパイラならループは 何も仕事をしてないことに気が付いて最適化の際にまったく取り除い てしまうかもしれない。 References: H&S Sec. 18.1 pp. 398-9; PCS Sec. 12 pp. 197-8,215- 6; POSIX Sec. 4.5.2. 19.38: Control-Cのようなキーボード割り込みを捕まえたり無視するの はどうすればよいか。 A: 基本的な手順は、signal()を呼んで、 #include signal(SIGINT, SIG_IGN); のように割り込みシグナルを無視するとか、 extern void func(int); signal(SIGINT, func); として割り込みシグナルを受け取ったら関数func()に制御が移るよう にする。 Unixのようなマルチタスクのシステムでは、もう少し手の込んだ以下 のような技法を使うほうがよい。 extern void func(int); if(signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, func); テストと余分にsignal()の呼び出しを用意することでフォアグランド で打ち込まれて発生したキーボード割り込みがうっかりバックグラン ドで走っているプログラムに割り込みがかからないようにしている (どんなシステムで動かすにしても、このようにsignal()を呼ぶよう にコーディングしても悪いことにはならない)。 システムによっては、キーボードの割り込みの処理は端末の入力を処 理するサブシステムの特定のモードの機能である。 システムによってはキーボードの割り込みを調べるのは、プログラム が入力を読み込んでいるときにだけ実行され、どの入力ルーチンが呼 ばれているかによってキーボード割り込みの処理が変わってしまう (そもそも入力ルーチンが動いているかどうかによる)。MS-DOSシステ ムではsetcbrk()またはctrlbrk()が必要となるかもしれない。 References: ANSI Secs. 4.7,4.7.1; ISO Secs. 7.7,7.7.1; H&S Sec. 19.6 pp. 411-3; PCS Sec. 12 pp. 210-2; POSIX Secs. 3.3.1,3.3.4. 19.39: 浮動小数点の例外を扱う気の利いた方法は。 A: 多くのシステムで、matherr()というルーチンを定義することができ る。このルーチンはの中にある数学ルーチンで起きたエラー のような、ある種の浮動小数点のエラーが発生すると呼ばれる。また、 signal()(上の質問19.38を参照)を使ってSIGFPEを捕まえることがで きるだろう。質問14.9を参照のこと。 References: Rationale Sec. 4.5.1. 19.40: えーっと、どうやってソケットを使えばいいのか。ネットワークは。 クライアント/サーバーのアプリケーションの書き方は。 A: 上のすべての質問はこのFAQの範囲外で、C言語よりは使用するネット ワークの設備との関係のほうが強い。この件に関するよい本としては Douglas Comerの三部作であるInternetworking with TCP/IPや W. R. StevensのUNIX Network Programminが挙げられる。(ネットワー クそのものの上にもたくさんの情報が流れている) 19.40b: BIOSコールをどうやって使えばいいのか。どうすれば常駐ソフトが書 けるのか A: こういうのは特定のシステムに特有な話である(十中八九、MS-DOSが 走っているPC互換機だろう)。 特定のシステムの話を扱うcomp.os.msdos.programmerのようなニュー スグループやそういうグループのFAQからのほうがもっと情報が得ら れるだろう。その他の素晴らしい情報源としてはRalf Brownの割り込 みの一覧表がある。 19.41: そんなこといっても、そんな標準でないシステム依存の関数を使うわ けにはいかない。私のプログラムはANSI規格に適合してなければいけ ない。 A: ついてないね。君が要求事項を誤解してるか、そういう要求を満たす のは不可能なのかのどちらかだ。ANSI/ISO標準Cは上のような事柄を どうやって実行するのかを定義するものでは全くない。それは言語の 規格であって、オペレーティングシステムの規格ではない。 国際的な規格で、こうした点について取り組んでいるのは POSIX((IEEE 1003.1, ISO/IEC 9945-1)である。(Unixだけではなく) 多くのオペレーティングシステムが今ではPOSIX互換のプログラミング インタフェースを用意している。 システム依存の機能を、移植するシステムごと に書き直す少数のファイルの少数のルーチンに任せて、プログラムの ほとんどの部分をANSI規格適合にすることは可能であるし、そうする ことが望ましい。 20章 その他 20.1: 関数から複数の値を返すことはできるか。 A: 値を格納する領域をいくつか起動する側で用意して、それらの領域を 指すポインタを引数として渡し、関数にポインタの先に値を埋めても らう。あるいは、関数の戻り値を構造体にして、その構造体に希望の 値を設定してもらう。あるいは(最後の手段として)グローバル変数を 使うことを考える。質問2.7, 4.8, 7.5を参照のこと。 20.3: コマンド行の引数をどうやって手にいれることができるか。 各引数は配列argvによって指されている。main()はargvを引数として 起動される。質問13.7と19.20も参照のこと。 References: K&R1 Sec. 5.11 pp. 110-114; K&R2 Sec. 5.10 pp. 114- 118; ANSI Sec. 2.1.2.2.1; ISO Sec. 5.1.2.2.1; H&S Sec. 20.1 p. 416; PCS Sec. 5.6 pp. 81-2, Sec. 11 p. 159, pp. 339-40 Appendix F; Schumacher, ed., _Software Solutions in C_ Sec. 4 pp. 75-85. 20.5: どうすれば、ワードの大きさが異なったり、バイトの並びかたが異なっ たり、浮動小数点数の内部表現が異なるようなマシンでも読めるようにデー タファイルに書き込むことができるのか。 A: 最も移植性が高い解はテキストファイル(通常はASCII)を使うこと である。fprintf()を使って書き込み、fscanf()の類を使って読む(同 様の助言はネットワークのプロトコルにもあてはまる)。「テキスト ファイルは大きすぎて、その読み書きは遅すぎる」という意見は疑っ てかかること。その効率はしばしば実用に耐えるものであるし、マシ ン間で容易にデータ交換できることや標準的な道具だけで操作できる という利点は否定できない事実である。 バイナリフォーマットを使わなければならない場合でも、 標準化されたフォーマットを利用して、移植性を 向上させたり、既存の I/Oライブラリをうまく使うことが可能である。標準のフォーマット としてはSUNのXDR(RFC 1014)、OSIのASN.1(CCITTのX.409やISO 8825 で「基本符号化則:Basic Encoding Rules」として参照されている)、 CDF、netCDF、HDFが存在する。質問2.12や12.38を参照のこと。 References: PCS Sec. 6 pp. 86,88. 20.6: char *の変数があって、その変数は関数の名前を指している。どうす ればこの関数を呼ぶことができるか。 A: 一番単純な方法は、関数の名前と関数へのポインタの対応表を用意 することである。 int func(), anotherfunc(); struct { char *name; int (*funcptr)(); } symtab[] = { "func", func, "anotherfunc", anotherfunc, }; そうして名前を求めてテーブルを探し、名前に対応する関数へのポイ ンタを使って関数を起動すればよい。質問2.15と19.36も参照のこ と。 References: PCS Sec. 11 p. 168. 20.8: ビットの集合や配列はどうやって実装すればいいのか。 A: charやintの配列を使う。マクロを使って、配列のしかるべき要素 にある望みのビットにアクセスできるようにする。以下にcharの配列 を使った簡単なマクロの例を紹介する。 #include /* for CHAR_BIT */ #define BITMASK(b) (1 << ((b) % CHAR_BIT)) #define BITSLOT(b) ((b) / CHAR_BIT) #define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b)) #define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b)) (がないときはCHAR_BITの代わりに8を使う) References: H&S Sec. 7.6.7 pp. 211-216. 20.9: マシンの並び順(byte order)がビッグエンディアンかリトルエンディ アンかはどうやって調べればよいか。 A: ポインタを使う手がある。 int x = 1; if(*(char *)&x == 1) printf("little-endian\n"); else printf("big-endian\n"); 共用体を使って調べることも可能である。 質問10.16も参照のこと。 References: H&S Sec. 6.1.2 pp. 163-4. 20.10: 整数をどうやれば2進数や16進数に変換できるか。 A: 自分の質問の内容を本当に理解しているか。整数は内部的には2進数 で保存されている。だから、数が8進だとか10進だとか16進など自分 に都合いいN進法で(底で)あると考えるのはたいていの場合間違いで ある。どの底で(何進法で)数を表わすかは外界から数を読んだり書い たりするときにだけ問題になる。 ソースコードの上では、10進法以外の場合は数の前に0や0x(それぞれ 8進、16進を表わす)を付けて表わす。入出力中は、整形済みの数が何 進数かは、printfやscanfの類では書式指定子(%d, %o, %xなど)を選 択することで、strtol()やstrtoul()では3番目の引数で制御可能であ る。ただしバイナリ入出力中は、ここでも何進法かはどうでもいい ことになる。 "バイナリ"入出力についてもっと知りたいならば、質問2.11を参照 のこと。質問8.6や13.1も参照のこと。 References: ANSI Secs. 4.10.1.5,4.10.1.6; ISO Secs. 7.10.1.5,7.10.1.6. 20.11: 2進数の定数(0b101010のように)を使うことはできるか。2進数用の printf()の書式は存在するか。 A: 2進数の定数は存在しないし、2進数用の書式も存在しない。底2の(2 進数の)文字列による表現をstrtol()を使って整数に変換することは 可能である。 20.12: 値の中で立っているビットの数を数えるもっとも効率のよい方法を教 えて欲しい。 A: この手の"ビットをいじる問題"は参照用テーブル(lookup table)を使 うことで、高速かつ能率よく処理することができる(ただし以下の質 問20.13を参照のこと)。 20.13: どうすれば、このコードをもっと効率的にすることができるか。 A: よいアルゴリズムを選んで、それを注意深く実装して、プログラムが 余分なことまでしないようにする。たとえば、文字をコピーするルー プを局所的にどんなに最適化しても文字をまったくコピーしないコー ドには勝てない。 効率について心配するなら、いくつかのことがらを視野にいれておく ことが大事である。まず、効率はとても人気のある話題だけれど、人 が考えているほど、たいした問題ではない。たいていのプログラムの たいていのコードは処理速度を要求されているわけではない。処理速 度を要求しないコードの場合、最大限に効率化を計るより、わかりや すさや移植性を考えるほうがずっと大事である(コンピューターは非 常に高速である。だから"能率の悪い"コードも目立った遅れなく走る かもしれないということをお忘れなく)。 プログラムの中でどこが問題点になるか予想することは非常に困難な ことで有名である。効率に関心があるのならプログラムのどの場所に 関心を置くべきか調べるために、処理の輪郭を記録(profiling)する ソフトウェアを使うことは大事である。たいていは、実際の計算時間 はI/Oやメモリの割り付けなどの周辺装置の操作に集中する。そして これらの作業は、バッファリングやキャッシングの技を使って高速化 することができる。 コードの処理時間の制約が厳しいところでも、コードの詳細を局所的 に最適化しなければならないほど重要であることはない。しばしば提 案される"効率的なコーディングの技"の多くは(たとえば2のべき乗を 掛けるときに掛け算の代わりにシフト演算子をつかうこと)、単純なコ ンパイラでも自動的にやってくれる。不器用な"最適化"の試みはコー ドをふくらませることで性能を悪化させる可能性さえあるし、その移 植性が高いことはめったにない(すなわち、あるマシンでは高速化さ れかもしれないけれど、他のマシンでは遅くなってしまう)。いずれ にせよ、コードをいじってもせいぜい効率が線形に改善されるだけで ある。大きな見返りはよりよいアルゴリズムから得られる。 効率化のトレードオフに関する議論や、効率化が本当に重要なときの 良い助言についてはKernighanとPlaugerの『プログラム書法』の7章 やJon Bentleyの『プログラム改良学』を参考のこと。 20.14: ポインタは本当に配列よりも高速なのか。関数呼び出しをするとど れだけ遅くなるのか。++iはi=i+1よりも高速か。 A: これらの質問や多くの類似の質問への正確な解答は、もちろん使用し ているプロセッサやコンパイラに依存する。結果が知りたければテス トプログラムで注意して測定するしかない(多くの場合、その差は非 常に小さいので、差を知るのに何万回もくり返しが必要となる。もし 手に入るのなら、両方の技を使ったコードが別のコードを生成したか どうか、コンパイラの生成したアセンブラ出力を見比べてみること)。 たいていは大きな配列の中をアクセスしてまわるのにポインタを使う ほうが、配列の添え字を使うより高速であるが、その反対のプロセッ サーも存在する。 関数呼び出しは、インラインで記述するよりも、それだけ明らかに遅 くなるけれど、モジュール化やコードのわかりやすさに役に立ってい ることを考えれば、使わない理由なんてめったに存在しない。 i = i + 1といった書き方を書き直す前に、相手はCコンパイラであっ てキー入力をプログラムできる電卓を相手にしているのではないこと をお忘れなく。よくできたコンパイラならi++、++i、i = i + 1、ど れについても同じコードを生成する。i =i + 1を押しのけて++iやi += 1を使うのは、書き方の面からであって効率を問題にしているから ではない。(質問3.12も参照のこと。) 20.17: 文字列の内容によって処理を切り替える方法はあるか。 A: 直接には不可能である。文字列を整数コードに対応させる別の関数を 用意して、その整数コードを使って処理を切り替えるのが適切な場合 がある。もちろん、その他の手としては、strcmp()に頼って普通に if/elseを並べることが考えられる。質問10.12, 20.18, 20.29を参照 のこと。 References: K&R1 Sec. 3.4 p. 55; K&R2 Sec. 3.4 p. 58; ANSI Sec. 3.6.4.2; ISO Sec. 6.6.4.2; H&S Sec. 8.7 p. 248. 20.18: caseのラベルに定数以外(範囲指定とか、こちらの好きな式など)を持っ てくることはできるか。 A: できない。switch文はもともとの設計でコンパイラがコードを変換す るのが楽なように単純になっている。だからcaseのラベルは単体の定 数の整数式に限られている。一つの式に複数のcaseのラベルを付ける ことは可能である。こうすれば、すべての場合をいちいち記入するこ とを面倒に思わなければ、小さな範囲を覆うことができる。 任意の範囲指定や定数以外の式をもってきたいなら、if/elseをずら ずら並べるしかない。 質問20.17も参照のこと。 References: K&R1 Sec. 3.4 p. 55; K&R2 Sec. 3.4 p. 58; ANSI Sec. 3.6.4.2; ISO Sec. 6.6.4.2; Rationale Sec. 3.6.4.2; H&S Sec. 8.7 p. 248. 20.19: returnの後ろに来る式をくくる括弧は本当に省略可能か。 A: 省略可能だ。 大昔、Cの初期には、必要であった。そのころにCを学んだ人がたくさ んいるし、そのころ書かれたコードが今でも世の中に出まわっている。 それで括弧が今でも必要であるという考えが広まっている。 (ちなみにsizeof演算子も、オぺランドが変数か単項式なら、括弧は 省略可能である。) References: K&R1 Sec. A18.3 p. 218; ANSI Sec. 3.3.3, Sec. 3.6.6; ISO Sec. 6.3.3, Sec. 6.6.6; H&S Sec. 8.9 p. 254. 20.20: なぜC言語のコメントは入れ子にすることができないのか。コメント を含むコードをコメントアウトするのはどうすればよいか。引用符で かこまれた文字列の中にコメントがあるのは文法上許されるのか。 A: Cのコメントが入れ子にできないのは、PL/Iのコメントが入れ子にで きないからである。CはPL/Iからコメントについてのアイデアを借用 している。コメントを含むような大きな領域を"コメントアウト"する ときは#ifdefや#if 0を使ったほうがいい(ただし、質問11.19を参照)。 /*や*/は二重引用句でくくられた文字列のなかでは特別な意味を持た ない。だからこれらの文字列がコメントを意味する事はない。なぜな らプログラムが(とくにに出力としてCのコードを生成するプログラム が)、これらの文字列を出力したいかもしれないから。 C++風の//で始めるコメントは現在のところCでは文法上許されていな いことに注意。だから、Cプログラムで使うのはよい考えではない(た とえ使用中のコンパイラが拡張機能として対応しているとしても)。 References: K&R1 Sec. A2.1 p. 179; K&R2 Sec. A2.2 p. 192; ANSI Sec. 3.1.9 (esp. footnote 26), Appendix E; ISO Sec. 6.1.9, Annex F; Rationale Sec. 3.1.9; H&S Sec. 2.2 pp. 18-9; PCS Sec. 10 p. 130. 20.24: どうしてCには入れ子の関数が用意されていないのか。 A: 呼ぶ側の関数のローカル変数に正しくアクセスするように入れ子の関 数を用意することは簡単な話ではない。そういうわけで、入れ子の関 数はCが単純さを失わないように故意に省略された。(gccは拡張機能と して入れ子の関数を許している。) 入れ子の関数があったとしたら使 えそうな状況の多くの(例:qsortの比較に使う関数)少し面倒だけれど 要求を満たす解としては、static宣言した隣り合う関数を使い、 static変数で情報をやりとりする方法がある。(そういう関数間で情 報をやりとりが必要な場合のもっときれいな解は、必要なコンテキス トを含んだ構造体へのポインタをやりとりすることである。) 20.25: どうすればCからFORTRAN(あるいはC++、BASIC、Pascal、Ada、LISP) の関数を起動することができるか(あるいはその反対は)。 A: 解答は、使用中のマシンやコンパイラが関数を起動する方法に依存す る。ひょっとしたらまったく不可能かもしれない。コンパイラの資料 を注意深く読むこと。ときどき「複数のプログラム言語を使ったプロ グラミングの手引き」が載っている。それでも引数を渡す方法や、実 行時の適切な立ち上がりを保証することは、神秘的ですらある。その 他にGlenn Geers作のFORT.Zからも手掛かりが得られる。このプログ ラムはsuphys.physics.su.oz.auのsrcディレクトリに置かれている。 cfortran.hというCのヘッダファイルは、世の中に出まわっている 多くのマシン上で、C/FORTRAN間のインタフェースを簡単にする。こ れはzebra.desy.de(131.169.2.244)よりanonymous ftpで手に入れる ことができる。 C++では外部関数の宣言に"C"修飾子を付けることで、Cの関数の起動 方法に従って起動することを指定することができる。 References: H&S Sec. 4.9.8 pp. 106-7. 20.26: Pascal(あるいはFORTRAN、LISP、Ada、awk、"古いC")をCに変換する プログラムを知らないか。 A: いくつかの自由に配布可能なプログラムが存在する。 p2c Dave Gillespieによって書かれ、comp.sources.unixに1990 年4月(Volume 21)に投稿された。csvax.cs.caltech.eduから anonymous ftpすることもできる。ファイル名は pub/p2c-1.20.tar.Z。 ptoc これもPascalをCに変換するツール。これはPascalで書かれ ている(comp.sources.unixのVolume 10、パッチはVolume 13?にある)。 f2c ベル研とBellcoreとカーネギーメロン大学の共同開発による FORTRANのプログラムをCに変換するソフトウエア。f2cにつ いて知りたければ「send index from f2c」というメッセー ジと共にnetlib@research.att.comあるいは reseach!netlibにメールを出すこと。(research.att.comの ディレクトリdist/f2cからのanonymous ftpも可能である。) このFAQの編者は、商品となった変換ツールや、ここに挙げていない 言語との間の変換ツールのリストを用意している。 質問11.31と18.16も参照のこと。 20.27: C++はCの上位集合か。C++のコンパイラをCのコードのコンパイルに使 うことはできるか。 A: C++はCに起源を持ち、大部分Cに基づく。しかしC言語としては正しい 構造であるが、C++では文法違反なものがいくつか存在する。逆に、 ANSI Cはプロトタイプやconstのような、いくつかの機能をC++から受 け継いでいる。よってどちらが上位集合とか下位集合ということはい えない。これらの違いにもかかわらず、Cのプログラムの多くはC++の 環境で正しくコンパイルできるし、最近のコンパイラの多くはCとC++ 両方のコンパイルモードを用意している。質問8.9と20.20も参照のこと。 References: H&S p. xviii, Sec. 1.1.5 p. 6, Sec. 2.8 pp. 36-7, Sec. 4.9 pp. 104-107. 20.28: "近似の"strcmpとでもいうようなルーチンが欲しい。つまり二つの文 字列が近い、けれど必ずしもぴったりでなくてもよい、ことを調べる ルーチンが欲しい。 A: 文字列のおよその一致に関するよく書けた情報やアルゴリズムが、参 考文献の役に立つ一覧と共に、Sun WuとUdi Manberの論文"AGREP -- A Fast Approximate Pattern-Matching Tool"に載っている。 その他のやり方はとしては「soundex」がある。これは同じ様な発音 の単語を同じ数値のコードに写像する。soundexは同じ様な発音の名 前を捜すのに(ちなみに電話帳の助けになるように)設計されたが、任 意の単語を処理するようにすることもできる。 References: Knuth Sec. 6 pp. 391-2 Volume 3; Wu and Manber, "AGREP -- A Fast Approximate Pattern-Matching Tool" . 20.29: ハッシュ法とは。 A: ハッシュ法とは、文字列を整数に写像する処理のことをいう。通常、 整数は比較的小さな範囲のものを使う。「ハッシュ関数」は文字列 (または、その他のデータ構造を)を有界の整数("ハッシュバケツ (hash bucket)")に写像する。この整数は配列のインデックスとして 使えるし、くり返しの比較に使うのも容易である。(すぐわかるよう に、巨大になる可能性のある文字列の集合を整数の小さな集合に写像 すれば一意にはならないものである。ハッシュ法を使ったどんなアル ゴリズムも、この"衝突"が起こることを考慮にいれなければならない。) これまでに、さまざまのハッシュ関数や関連するアルゴリズムが開発 されてきた。これらを満足に論じることは、このFAQの範囲を越えて いる。 References: K&R2 Sec. 6.6; Knuth Sec. 6.4 pp. 506-549 Volume 3; Sedgewick Sec. 16 pp. 231-244. 20.31: 日付から曜日を求める方法は。 A: ルーチンmktime()かlocaltime()を使うか(Q12.6、Q12.7を参照。ただ しtm_hourが0のときにはDST adjustmentに注意すること)、Zellerの 公式(sci.mathのFAQを参照)を使うか、するか、あるいは坂本智彦が ポストした以下の気の利いたコードを試すこと。 dayofweek(y, m, d) /* 0 = Sunday */ int y, m, d; /* 1 <= m <= 12, y > 1752 or so */ { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; } (Copyright 1993, Tomohiko Sakamoto) 質問13.14と20.32も参照のこと。 References: ANSI Sec. 4.12.2.3; ISO Sec. 7.12.2.3. 20.32: 紀元2000年はうるう年か。(year % 4 == 0)はうるう年かどうかの正 確なテストか。 A: 一つめの問題の答えはYES、二つめはNOである。グレゴリオ暦のカレ ンダー用の正しい式は以下の式で表わされる。 year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) 詳細については、まともな天文学年鑑かその他の参考書を見ること。 (永遠に続く議論を未然に防ぐために言っておく。4000年に1度うる う年が来ると主張する文献は間違っている。) 質問13.14も参照のこと。 20.34: さて問題です。どうやれば出力として、自分自身のソースコードを産 み出すコードをどうやったら書けるか。 A: 本当に移植性の高い自己再生プログラムを書くのは大変難しい。これ は特に、一重/二重引用符の使い方、文字集合(ASCII, EBCDIC...) に何を使うかからくる困難による。 以下は古典的な例である(普通は1行で紹介される。しかし最初に走っ たときに自身を"修正"する) char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);} (このプログラムは、この種のプログラムの多くと同じように二重引 用符 " がASCIIのように34であると決めてかかっている.) 20.35: "ダフのデバイス(Duff's Device)"とは。 A: とんでもなく曲がりくねって展開されたバイトコピーの関数である。 これはTome DuffがLucasfilmに在籍中に考え出した。"古典的"な形式 では、以下のようになる。 register n = (count + 7) / 8; /* count > 0 であると仮定する */ switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); } countバイトだけfromによって指された配列からtoで指された場所ま でコピーする(toが指している先はメモリマップされたデバイスの出 力レジスタである。だからincrementされない)。残りのバイトの処 理する問題を(countが8の倍数でないときに)、swtich文に一度に8バ イトコピーするループを差し込むことで解決している。驚くなかれ、 swtich文に入れ子になっているブロックの中にcaseのラベルを埋めこ むことは合法である。この技のCで開発する人達や世の中への彼の声 明によれば、このCのswtichの構文は、特に"下に落ちる(fall through)"動きが、昔から物議をかもしてきた。「このコードはそう いう議論に論拠を出すことになる。ただし、賛成意見なのか反対意見 なのかはよくわからない。」 20.36: 次の国際難解Cコードコンテスト:International Obfuscated C Code Contest(IOCCC)はいつ開かれるのか。どうすれば今回や昔の授賞作を 手に入れることができるのか。 A: コンテストのスケジュールは、授賞者の発表されるUSENIXの会議の日 付に縛られている。このFAQを書いている時点では、この年に一度行 われるコンテストは10月に開かれる。 最新のルールやその外の情報 を得るにはSubject:に「send rules」と書いて {apple,pyramid,sun,uunet}!hoptoad!judges or judges@toad.com に送ればよい(これらのアドレスは出展の申し込み用ではない)。 コンテストの受賞者は1月に行われる冬のUSENIXの会議で最初に発表 され、その後ネットに投稿される。昔の(1984年以降の)受賞作品は uunetの~/pub/iocccというディレクトリから手に入れることができる (質問18.16を参照)。http://reality.sgi.com/csp/ioccc/も参照のこと。 どうやっても手に入れられなければ、過去の授賞作は上記のアドレス にSubject:として「send YEAR」を付けた電子メールを送ることによっ て得られる。ここでYEARは4けたの年か、年度の範囲指定、あるいは 「all」である。 20.37: K&R1で述べられていたentryというキーワードは。 A: このキーワードはFORTRANのように、関数が複数の異なる名前のエント リーポイントを持つことを許すことを考えて予約されていた。この機 能が実現された例を知っている人は誰もいない(このキーワードを使っ てどういう構文が考えられていたのかもだれも知らない)。この機能 は撤回され、ANSI Cのキーワードにはならなかった。(質問1.12も参 照のこと。) References: K&R2 p. 259 Appendix C. 20.38: そもそも、「C」という名前の由来は。 A: CはKen Thompsonの実験的なプログラミング言語Bから派生したもので ある。BはMartin RichardsのBCPL(Basic Combined Programming Language)から着想を得ている。BCPLはCPL(Cambridge Programming Language)の仕様を記述したものであった。しばらく、Cの後継言語は Dではなく、P(BCPLの3番目の文字)という名前になるのではないかと 噂されていた。しかしもちろん今日一番目につく後継言語はC++であ る。 20.39: 「char」というのはどう発音するのか。 A: C言語のキーワードの「char」の発音の仕方は少なくとも3通りはある。 「char(チャー)」、「care(ケア)」、「car(カー)」のように発音す る。("キャラクター"でもよい)どれを使ってもいい。 (訳注:カタカナで発音を表記した『UNIX用語由来/読み方辞書』が http://www.meitetsu.co.jp/docs/dic/unix-term-dic.htmlから 入手可能である。) 20.40: このリストをもう一部欲しいがどうしたらよいか。過去の版はどうか。 A: 最新版はftp.eskimo.comのディレクトリu/s/scs/C-faq/から入手する ことができる。ネットからも引っ張ってくることができる。通常、ニュー スグループcomp.lang.cに月の始めに投稿される。Expires:行が付い ているので一ヶ月丸々消えないで残っている。並行して、簡易版も入 手可能である(投稿もされている)。大きく更新した版には変更の一覧 も用意している。 このFAQはさまざまな形でニュースグループcomp.answersや news.answersに投稿されている。いくつものサイトがこのFAQも含め て、news.answersへの投稿やその他のFAQを保管している。サイト rtfm.mit.edu(ディレクトリpub/usenet/news.answers/C-faq/と pub/usenet/comp.lang.c/)やサイトftp.uu.net (ディレクトリ usenet/news.answers/C-faq/) は、そのようなサイトのうちの2つで ある。archieサーバー(質問18.16参照)はそのようなサイトを見つけ る助けになる。archieに"prog C-faq"と聞いてみろ。ftpが使えない 環境なら、rtfm.mit.eduにあるメールサーバーを使ってFAQを手にい れることができる。まずは、本文に「help」とだけ書いて mail-server@rtfm.mit.eduに送る。その他の情報はnews.answersの meta-FAQ listから得られる。 このFAQの別の形態のものがWorld-Wide Webで読むことができる。3つ のURLは(それぞれ形態は異なる)、 http://www.lysator.liu.se/c/c-faq/index.htmlと http://www.hut.fi/~jkorpela/CFAQ.htmlとhttp://www.cis.ohio- state.edu/hypertext/faq/usenet/C-faq/top.htmlである。(以下で紹 介する本に対応する)拡大版はもうすぐ、たぶん1995年の9月半ばに使 えるようになる。すべてのFAQを指すURL(話題による検索ができるも の)はhttp://www.cis.ohio- state.edu/hypertext/faq/usenet/FAQ-List.htmlと http://www.luth.se/wais/にある。 このFAQの拡張した版はAddison-Wesleyより『C Programming FAQs: Frequently Asked Questions』(ISBN 0-201-84519-9)として1995年11 月に出版されている。 (訳注: 日本語版はトッパンより『CプログラミングFAQ Cプログラミ ングのよく尋ねられる質問』(ISBN 4-8101-8097-2)として出版されて いる。) このリストは発展し続ける資料である。単に今月の興味深い質問への 回答の寄せ集めではない。昔のリストは時代遅れで大した情報を持っ ていない。例外は、ときどきある入力ミスで、今回のリストに含まれ ていないものである。 参考文献 Americal National Standards Institute, _American National Standard for Information Systems -- Programming Language -- C_, ANSI X3.159-1989 (質問11.2参照). [ANSI] Americal National Standards Institute, _Rationale for American National Standard for Information Systems -- Programming Language -- C_ (質問11.2参照). [Rationale] Jon Bentley, _Writing Efficient Programs_, Prentice-Hall, 1982, ISBN 0- 13-970244-X. (邦訳:プログラム改良学 近代科学社 ISBN4-7649-0159-5) G.E.P. Box and Mervin E. Muller, "A Note on the Generation of Random Normal Deviates," _Annals of Mathematical Statistics_, Vol. 29 #2, June, 1958, pp. 610-611. David Burki, "Date Conversions," _The C Users Journal_, February 1993, pp. 29-34. Ian F. Darwin, _Checking C Programs with lint_, O'Reilly, 1988, ISBN 0- 937175-30-7. David Goldberg, "What Every Computer Scientist Should Know about Floating-Point Arithmetic," _ACM Computing Surveys_, Vol. 23 #1, March, 1991, pp. 5-48. Samuel P. Harbison and Guy L. Steele, Jr., _C: A Reference Manual_, Fourth Edition, Prentice-Hall, 1995, ISBN 0-13-326224-3. [H&S] (邦訳:詳細C言語:H&Sリファレンス 日本ソフトバンク ISBN4-89052-050-3) Mark R. Horton, _Portable C Software_, Prentice Hall, 1990, ISBN 0-13- 868050-7. [PCS] (邦訳:ポータブルCプログラミング トッパン) Institute of Electrical and Electronics Engineers, _Portable Operating System Interface (POSIX) -- Part 1: System Application Program Interface (API) [C Language_, IEEE Std. 1003.1, ISO/IEC 9945-1. International Organization for Standardization, ISO 9899:1990 (see question 11.2). [ISO] Brian W. Kernighan and P.J. Plauger, _The Elements of Programming Style_, Second Edition, McGraw-Hill, 1978, ISBN 0-07-034207-5. (邦訳:プログラム書法第2版 共立出版) Brian W. Kernighan and Dennis M. Ritchie, _The C Programming Language_, Prentice-Hall, 1978, ISBN 0-13-110163-3. [K&R1] (邦訳:プログラミング言語C 共立出版) Brian W. Kernighan and Dennis M. Ritchie, _The C Programming Language_, Second Edition, Prentice Hall, 1988, ISBN 0-13-110362-8, 0-13-110370-9. [K&R2] (邦訳:プログラミング言語C 第2版 共立出版) Donald E. Knuth, _The Art of Computer Programming_. Volume 1: _Fundamental Algorithms_, Second Edition, Addison-Wesley, 1973, ISBN 0- 201-03809-9. Volume 2: _Seminumerical Algorithms_, Second Edition, Addison-Wesley, 1981, ISBN 0-201-03822-6. Volume 3: _Sorting and Searching_, Addison-Wesley, 1973, ISBN 0-201-03803-X. [Knuth] (邦訳:基本算法) Andrew Koenig, _C Traps and Pitfalls_, Addison-Wesley, 1989, ISBN 0-201- 17928-8. [CT&P] (邦訳:Cの落とし穴 トッパン) Stephen K. Park and Keith W. Miller, "Random Number Generators: Good Ones are Hard to Find," _Communications of the ACM_, Vol. 31 #10, October, 1988, pp. 1192-1201 (also technical correspondence August, 1989, pp. 1020-1024, and July, 1993, pp. 108-110). P.J. Plauger, _The Standard C Library_, Prentice Hall, 1992, ISBN 0-13- 131509-9. Thomas Plum, _C Programming Guidelines_, Second Edition, Plum Hall, 1989, ISBN 0-911537-07-4. William H. Press, Saul A. Teukolsky, William T. Vetterling, and Brian P. Flannery, _Numerical Recipes in C_, Second Edition, Cambridge University Press, 1992, ISBN 0-521-43108-5. Dale Schumacher, Ed., _Software Solutions in C_, AP Professional, 1994, ISBN 0-12-632360-7. Robert Sedgewick, _Algorithms in C_, Addison-Wesley, 1990, ISBN 0-201- 51425-7. Charles Simonyi and Martin Heller, "The Hungarian Revolution," _Byte_, August, 1991, pp.131-138. David Straker, _C Style: Standards and Guidelines_, Prentice Hall, ISBN 0-13-116898-3. Steve Summit, _C Programming FAQs: Frequently Asked Questions_, Addison- Wesley, 1995, ISBN 0-201-84519-9. [The book version of this FAQ list.] Sun Wu and Udi Manber, "AGREP -- A Fast Approximate Pattern-Matching Tool," USENIX Conference Proceedings, Winter, 1992, pp. 153-162. 改訂されたIndian Hillsスタイルガイド(質問17.9参照)にも参考文献の一 覧が載っている。質問18.10も参照のこと。 謝辞 直接にあるいは間接的にこのFAQに貢献してくれた以下の皆さんに感謝する。 Jamshid Afshar, David Anderson, Tanner Andrews, Sudheer Apte, Joseph Arceneaux, Randall Atkinson, Rick Beem, Peter Bennett, Wayne Berke, Dan Bernstein, Tanmoy Bhattacharya, John Bickers, Gary Blaine, Yuan Bo, Mark J. Bobak, Dave Boutcher, Alan Bowler, Michael Bresnahan, Walter Briscoe, Vincent Broman, Stan Brown, John R. Buchan, Joe Buehler, Kimberley Burchett, Gordon Burditt, Scott Burkett, Burkhard Burow, Conor P. Cahill, D'Arcy J.M. Cain, Christopher Calabrese, Ian Cargill, Vinit Carpenter, Paul Carter, Mike Chambers, Billy Chambless, C. Ron Charlton, Franklin Chen, Jonathan Chen, Raymond Chen, Richard Cheung, Steve Clamage, Ken Corbin, Ian Cottam, Russ Cox, Jonathan Coxhead, Lee Crawford, Nick Cropper, Steve Dahmer, Andrew Daviel, James Davies, John E. Davis, Ken Delong, Norm Diamond, Bob Dinse, Jeff Dunlop, Ray Dunn, Stephen M. Dunn, Michael J. Eager, Scott Ehrlich, Arno Eigenwillig, Yoav Eilat, Dave Eisen, Joe English, Bjorn Engsig, David Evans, Clive D.W. Feather, Dominic Feeley, Simao Ferraz, Chris Flatters, Rod Flores, Alexander Forst, Steve Fosdick, Jeff Francis, Ken Fuchs, Tom Gambill, Dave Gillespie, Samuel Goldstein, Tim Goodwin, Alasdair Grant, Ron Guilmette, Doug Gwyn, Michael Hafner, Darrel Hankerson, Tony Hansen, Elliotte Rusty Harold, Joe Harrington, Des Herriott, Guy Harris, John Hascall, Ger Hobbelt, Jos Horsmeier, Syed Zaeem Hosain, Blair Houghton, James C. Hu, Chin Huang, David Hurt, Einar Indridason, Vladimir Ivanovic, Jon Jagger, Ke Jin, Kirk Johnson, Larry Jones, Arjan Kenter, Bhaktha Keshavachar, James Kew, Darrell Kindred, Lawrence Kirby, 北野 欽一, Peter Klausler, Andrew Koenig, Tom Koenig, Adam Kolawa, Jukka Korpela, Ajoy Krishnan T, Jon Krom, Markus Kuhn, Deepak Kulkarni, Oliver Laumann, John Lauro, Felix Lee, Mike Lee, Timothy J. Lee, Tony Lee, Marty Leisner, Don Libes, Brian Liedtke, Philip Lijnzaad, Keith Lindsay, Yen-Wei Liu, Paul Long, Christopher Lott, Tim Love, Tim McDaniel, J. Scott McKellar, Kevin McMahon, Stuart MacMartin, John R. MacMillan, Andrew Main, Bob Makowski, Evan Manning, Barry Margolin, George Matas, Brad Mears, Wayne Mery, De Mickey, Rich Miller, Roger Miller, Bill Mitchell, Mark Moraes, Darren Morby, Bernhard Muenzer, David Murphy, Walter Murray, Ralf Muschall, Ken Nakata, Todd Nathan, Taed Nelson, Landon Curt Noll, Tim Norman, Paul Nulsen, David O'Brien, Richard A. O'Keefe, Adam Kolawa, Keith Edward O'hara, James Ojaste, Hans Olsson, Bob Peck, Andrew Phillips, Christopher Phillips, Francois Pinard, Nick Pitfield, Wayne Pollock, Polver@aol.com, Dan Pop, Claudio Potenza, Lutz Prechelt, Lynn Pye, Kevin D. Quitt, Pat Rankin, Arjun Ray, Eric S. Raymond, Peter W. Richards, James Robinson, Eric Roode, Manfred Rosenboom, J. M. Rosenstock, Rick Rowe, Erkki Ruohtula, John Rushford, Kadda Sahnine, 坂本 智彦, Matthew Saltzman, Rich Salz, Chip Salzenberg, Matthew Sams, Paul Sand, DaviD W. Sanderson, Frank Sandy, Christopher Sawtell, Jonas Schlein, Paul Schlyter, Doug Schmidt, Rene Schmit, Russell Schulz, Dean Schulze, Chris Sears, Peter Seebach, Patricia Shanahan, Aaron Sherman, Raymond Shwake, Peter da Silva, Joshua Simons, Ross Smith, Henri Socha, Leslie J. Somos, Henry Spencer, David Spuler, Frederic Stark, James Stern, Zalman Stern, Michael Sternberg, Alan Stokes, Bob Stout, Steve Sullivan, Melanie Summit, Erik Talvola, Dave Taylor, Clarke Thatcher, Wayne Throop, Chris Torek, Steve Traugott, Ilya Tsindlekht, Andrew Tucker, Goran Uddeborg, Rodrigo Vanegas, Jim Van Zandt, Wietse Venema, Tom Verhoeff, Ed Vielmetti, Larry Virden, Chris Volpe, Mark Warren, Alan Watson, Kurt Watzka, Larry Weiss, Martin Weitzel, Howard West, Tom White, Freek Wiedijk, Tim Wilson, Dik T. Winter, Lars Wirzenius, Dave Wolverton, Mitch Wright, Conway Yee, Ozan S. Yigit, and Zhuo Zang。 , who have contributed, directly or indirectly, to this article. Thanks to the reviewers of the book-length version: Mark Brader, Vinit Carpenter, Stephen Clamage, Jutta Degener, Doug Gwyn, Karl Heuer, and Joseph Kent。 書籍版のreviewerのMark Brader, Vinit Carpenter, Stephen Clamage, Jutta Degener, Doug Gwyn, Karl Heuer, and Joseph Kentに感謝する。 特にKarl HeuerとJutta DegenerとMark Braderに、よりよいFAQのリストを作 るという終わりのない目的追求のために私の好みを物ともせず、ときには私の 我慢を越えた水先案内をしてくれたことに感謝する。 Special thanks to Karl Heuer, Jutta Degener, and particularly to Mark Brader, who (to borrow a line from Steve Johnson) have goaded me beyond my inclination, and occasionally beyond my endurance, in relentless pursuit of a better FAQ list. Steve Summit scs@eskimo.com この記事の著作権は1990年から1996年に渡ってSteve Summitに帰属す る。書籍『C Programming FAQs: Frequently Asked Questions』の内容を著者 と出版社の許可の元、社会への貢献のために使用している。このFAQは書籍版 を補足することを意図としている。内容は各国の著作権法によって守られる。 (訳注:日本語版の著作権は北野 欽一に帰属する。) The content is made available here and may be accessed freely for personal use but may not be republished without permission. Except as noted otherwise, the C code in this article is public domain and may be used without restriction. このFAQ内のCのコード(vstrcat(), error()など)はパブリックドメインで、何 の制限もなく使用してよい。 This article is Copyright 1990-1996 by Steve Summit. Content from the book _C Programming FAQs: Frequently Asked Questions_ is made available here by permission of the author and the publisher as a service to the community. It is intended to complement the use of the published text and is protected by international copyright laws. The content is made available here and may be accessed freely for personal use but may not be republished without permission. Except as noted otherwise, the C code in this article is public domain and may be used without restriction. 日本語版の謝辞 日本語版を出すにあたって以下の方に、様々な形で助けてもらいました。感 謝してます。 voidさん、川下 敬之さん、野口 恭子さん、遥夢さん、飯間 昇さん、星野 浩 志さん、結城 義敬さん、田辺 良則さん、坂本 智彦さん、フィンローダーさ ん、青木 和麻呂さん、太田 純さん、熊谷 典大さん(順不同) 最後に原著者のSteve Summitさんに、私の細かい質問に一々丁寧に答えても らったことを感謝します。