今までの説明でも、充分に「無知」な書き方であることは理解していただけ たでしょう。でも、本当の「恐怖」については、まだ説明していません。 似たようなものを2つ書き、その内容の整合性を確実に保つことは大変です。 もし、構造体 struct Panic { int snoopy; int charlie; };があったとき、メンバーに double lucy; を追加しなければならなくなりまし た。もし、一方のソースファイル中で struct Panic { /* Panic(a) */ int snoopy; int charlie; double lucy; };とし、別のソースファイル中で、 struct Panic { /* Panic(b) */ int snoopy; double lucy; int charlie; };としてしまったらどうなるでしょう。この2つの構造体はサイズが異なってし まいます。図5−2に、構造体のメモリレイアウトを示します。
共に、 struct Panic peanuts;により、変数peanutsが確保されていても、このPanicがどちらのPanicかによっ て、本当のパニックが起こります。 Panic(a)の構造体を使って、変数peanutsの実体をメモリ上に確保し、Panic(b)による extern struct Panic peanuts;があるとき、peanuts.snoopyとpeanuts.lucyは偶然にも対応していますが、 peanuts.charlieは違っています。(b)の方で、peanuts.charlieに代入すると、 どういうことになるでしょう。(a)の方に実体があるのですが、構造体の定義 に(b)を使っているため、構造体の先頭から16バイトの位置から4バイト分が メンバーcharlieのためのメモリだと思って動作します。ということは、(a)に よって確保した実体(メモリ)の範囲を外れているので、もし(b)の方で charlieに代入をすると、変数peanutsに割り当てたメモリの次のアドレスに入っ ている変数を破壊してしまいます。 逆に、(a)側でcharlieに代入しても、そこは(b)ではパディングなので、 charlieの値は不変のままです。そして、これはなかなか見つけられないバグ になってしまいます。 つまり、知らない間に、誰かに、貴重なデータを破壊され、プログラムが動 作しなくなってしまうのです。メモリ上で偶然にも隣に配置された変数への代 入によって破壊されるのです。もちろん、破壊された変数を追っかけ回しても、 まず原因はつかめません。「誰かにデータを破壊された」ことは分かっても、 その誰かがなかなか分からないまま、仕事の予定がどんどん遅れていくのです。 ■楽をしよう■例では、構造体のメンバーが延々と並んでいましたね。あれだけ汚く並んで いるものを、きちんと対応づけるのは至難ですね。解決方法は、以上に述べた ことを実行して、「楽」をすればいいのです。プログラムの信頼性を上げるには、プログラムを短くすることが一番です。 そして、ムダなファイルなど作らないことです。プログラムを全然書かなけれ ば、バグの入る余地など全くありません。「完璧」です。余分なプログラムを グダグダ書いたりするから、ノコノコとバグに入り込まれてしまうのです。だ から、いつも書いているように、「楽をする程、信頼度が向上」する訳です。 もう、この診断室の、座右の銘になっていますね。 そもそも、極めて似たものを、延々と作るなどというバカげた作業をしては いけません。そういう作業があったら、まず、「工夫はできないか」と考える べきです。あるいは、周りの優秀なプログラマに相談すべきです。何も言わず、 黙々とプログラムを書き続けている初心者がいたら、えてしてこのようなこと を延々としていることがあるので周りの人は注意しましょう。こういうバカな ことをして、会社の技術者のほとんどが、それがバカなことであるのに気付い ていないこともあり、気絶寸前になったこともあります。まあ、技術のない会 社は、有能なコンサルタントを見つけてください。何人もで、何ヵ月も掛かっ ても解決できなかった問題を、一瞬で解決してくれるかも知れません。
|
オープンソース |