茶々入れ2006年12月19日 17時38分01秒

突っ込みどころ満載なのでちょっと茶々入れしてみようと思う。

その一つに,C言語は非常に自由度の高いコーディングができることが挙げられます。例えば,if-elseの処理を1行で記述できるC/C++の三項演算子は便利な機能ですが,よく見ないと処理内容がよくわかりません(リスト1)。

三項演算子って、C ではよく悪者にされるよね。おいらは値を代入するシーンや値を return で返すシーンではそれなりに有用だと思っているし、演算順序が左→右であることから複合的な条件分岐も割と整理して記述できるという利点もあったりするんだけれども。

でも、確かに示されているコード例は、酷いね。せめて、

(msg[i] >= 'a' && msg[i] <= 'z') ?
  msg[i] += 'A' - 'a' : msg[i] -= 'A' - 'a';

なんて書かずに、

/* アルファベットの小文字なら大文字に、大文字なら小文字に置き換える */
msg[i] -= 'a' <= msg[i] && msg[i] <= 'z'    ? 'a' - 'A' :
          'A' <= msg[i] && msg[i] <= 'Z'    ? 'A' - 'a' :
          /* アルファベット以外の場合 */      0;

ぐらいには書いて欲しい。対応する ifelse 構文も、ブレースなしにしてあげた方が公平じゃね?

だいたい、C/C++ の文脈でいうところの「自由度の高さ」に、三項演算子に代表されるようないわゆる言語の文法・構文仕様自体は無関係だ。ていうか、それを言うんだったらむしろ Perl なんかの方が「(記述の) 自由度の高さによる弊害」は大きい。

C/C++ で「自由度が高い」って言ったら、それは記述の自由度のことではなくて、動作として実現できることの自由度の高さのことを指すべきだ。そしてそれは、すなわちプログラマーが背負わなければならない責任の範囲が広い、ということでもある。メモリー管理やファイル管理なんかはその際たる例。まぁ、その辺のことについてはその後に「不親切さ」という言葉を用いて説明されているのではあるが。。。

ちなみに IOCCC ってお祭りを支えているのは C 言語の改行に対する自由さであるように思う。改行に対する自由がない BASIC の方がよっぽど汚いプログラムは出来上がりやすいように思うぞ。あ、でも Python は別格かも。

Part 2 でいきなり FAQ をもってくるという構成自体は割と良いと思う。

Q2: C/C++をこれから勉強するのはムダ? JavaとかC#のほうがいいの?

誕生から30年(C++の場合は22年)経った今でも,C/C++はプログラマならぜひともマスターしておきたい言語です。主に利用する言語がJavaや C#になるとわかっている人でも,少なくともCだけはマスターすることをお勧めします。JavaやC#を使う人でも,コンピュータとプログラムの仕組みはきちんと理解しておくべきだからです。Cはそのために最適なプログラミング言語なのです。

某氏がどこかで「プログラミングの入門には、アセンブリ言語こそ相応しい」とおっさられていたのを思い出したw。最も、アセンブリ言語がメモリーと CPU の両方の動作を管理しなければならないものであるのに対して、C 言語は CPU の動作についてはコンパイラがだいたい面倒を見てくれるという違いはありますが (register 宣言? あんなもんはヒントに過ぎんではないか)。

逆にいえば、コンピュータとそこまで深くお関わり合いになりたいとは思わない人にとっては、その説明では学習の動機付けにはならないわけで。。。まぁ、プロの技術者としてそれはどうなの? っていう人の気持ちも分からないではないんだけどね。個人的には、論理的に仕事をこなしてくれるんであれば、その辺についてはどっちでもいいです、って感じかな。。。

ただ、これから学ぼうとしているのが Java や C♯ (どうでもいいけどそろそろ C# って書くの止めにしない? 別に *nix 方面の人が嘲って C# って書く分には構わんと思うし、そも英語圏の日常的に ascii しか使わない人たちにまで強要は出来ないけど、あきらかに MS 提灯記事なのに C# って書かれているのを見ると、さすがに MS が可哀想に思えてくる。。。ちなみに C# は「シーナンバー」? それとも「シーハッシュ」? あるいは「シーいげた」かな?) であるならば、これらは文法的に C から継承している流儀が多いので、そういう意味でも C を学んでおくことに損はないと思う。

Q4: C/C++はどうやって勉強したらいいの? バイブルのような本があるの?

しかし,多くの人は「ポインタ」で習得のペースががっくりと落ちることでしょう。ポインタはCの大きな特徴で,これをマスターできなければCをマスターしたとはいえません。ポインタは,それだけを扱う書籍があるほどの「壁」でもあります。お勧めしたいのは,ポインタの活用が不可欠な,アルゴリズムやデータ構造の勉強を並行して進めることです。実際の利用法を知ることが理解の助けになるからです。

この手の説明って定番なワケだけれども。。。じゃあ他の言語でいうところの「リファレンス」の扱いと「ポインタ」の扱いが徹底的に違っていて、それゆえに C のポインタは難しいのかというと、文法的なことに関してのみ言えば全然そんなことはないはずなのに、他の言語の「リファレンス」に比べると、どうにも C のポインタばかりがまるで聳え立つ高い壁であるかのように説明されがちなのはなんでなんだろう?

そろそろ、C で難しいのはポインタなのではなくて、「プログラマーが自分の責任でメモリーを確保し、開放しなければならない」点であることをちゃんと説明してくれる書物やサイトが増えてくれても良いように思うのだが。明らかに、BASIC が主流だった頃と今とでは状況は異なるのに、BASIC が主流だった頃と同じ論理で「ポインタは難しい」って語るのは、あんまりにも無責任すぎるんではないか?

Q5: CとC++の違いは何?

それぞれの構文の違いで一番最初に目に付くのは,C++ではクラスを使えるようになった点でしょう。当初,C++が「C with Classes(クラス機能の付いたC)」という名前だったのは有名な話です*1。さらに演算子オーバーロードやテンプレートなどもC++の特徴的な機能です。

クラスってなに? オーバーロードって? テンプレートって? これ、初心者の為の Q&A よね?

実装の差分を具体的に示すんであれば、クラスそのものは構造体に改良を加えた程度のものであって、実際にはコンストラクタ/デストラクタや継承、仮想関数などの追加の方がよっぽど重要であるように思うのですが。

で、それらの総称という意味で「クラス」という言葉を用いているのであれば、それはもっと抽象的に、「オブジェクト指向の導入」という言葉にでも置き換えるべきじゃね? それだったら、初心者でも、すぐには理解することは出来なくても、とりあえず聞いたことのある言葉に「あーあーあー」と頷くぐらいのことはできる。で、それが具体的にはどういうことなのかを、触りだけ説明することができれば、完璧。

「インライン関数」については概要がちゃんと説明されているのに対して、これらはやたらと不親切でアンバランスに見えますよ。

Q7: C/C++を始めるには,最初にコンパイラを買わないとダメですか?

そんなことはありません。ありがたいことに,無償で入手できるC/C++のコンパイラがあります。(...中略)

代表的なC/C++コンパイラとして,

などがあります(LSI C-86はCだけ)。ただし,これらはコマンドライン(「MS-DOSコマンド」または「コマンド プロンプト」)で利用するコンパイラですので,...

マテ。何故 VC++ 2005 Express を入れない? ていうか、Part3 を待つべくもなく、リストに入れておいてあげようよ。VC++ Toolkit 2003 なんてリンク先既に消えてんじゃねーか。つか、LSI-C86 ってまだ生きてたのね (^-^; 。

# BCC32 は今入手が困難な状態になっていた筈。そも、記事のリンク先として示されていた co.jp なサイトには繋がらんし、.com なサイトの Download ページとか覗いてもぜんぜん見当たらんかったりする。この辺とか、漁ってみれば、見つかるかも知れんけど、保証はできない。BCC はこれとかこれとかと組み合わせて使うとちょっとした物を作る程度ならなかなか快適だったりするのですが。。。

Q8: C++はオブジェクト指向プログラミング言語ですか?

以下、煮え切らない説明が延々と続く。。。もうね、簡潔にきっぱりと、「C++ は、オブジェクト指向で書くことできる言語です。Java などのように、オブジェクト指向の世界観を提供し、強要するような言語ではありません。」ぐらいでええやん。

Q9: Javaなら少しわかるんだけど,C++はJavaとどう違うの?

まずJavaプログラマが面食らうのは「クラスを作らなくてもよい」ことでしょう。アプリケーションがすべてクラスの集まりとして作られるJavaと根本的に異なる点です。だからといってC++のクラスがJavaより貧弱なわけではありません。例えばC++では,継承でクラスを作成する際に基底クラスを複数指定する「多重継承」が可能です。また,演算子の機能を任意のクラスに対して定義する「演算子オーバーロード」などの機能も持っています。

2点突っ込む。まず 1 点。「だからといって~」に続く記述から、「クラスを作らなくてもよい」ことがオブジェクト指向的に弱いことであるような印象を受けるが、オブジェクト指向的手法を強要されることに対する自由度は部品化コストや安全性とのトレードオフであり、それが必ずしも弱点であるとは思わない。Java が main ルーチンに辿りつくまでの工程は冗長に過ぎるし、オブジェクト指向の利点は作ることよりも利用することの方が大きいという側面からしても、C++ 的なアプローチの方が自然だという意見もある。

もう 1 点。「多重継承」や「演算子オーバーロード」を Java に対するアドバンテージであるかのように説明するのは、老練な Java プログラマーに笑いのネタを提供するだけなので止めて欲しい。Java には多重継承によるまずい設計が行われることと、多重継承が必要となりうるシチュエーションが存在することとのパラドックスを、interface という概念を提供することによってうまく解決している。それに、演算子オーバーロードはおいらも嫌いじゃないが、こいつが仕様として非常に難解なものであるが故に、多くのトラブルの元となっており、実際、プロの現場で演算子オーバーロードを活用しまくっている場面というのはめったに遭遇しない (それだけ一般には嫌がられているということだ)。iostream? getline なんて欠陥品そのものじゃないか。みんな fgets() 使ってるよ。その方が断然速いし。

Q11: コマンドラインのプログラムは書けるようになりました。この先Windowsアプリを作るにはVisual C++が必要ですか?

Windowsアプリケーションを作るために,必ずしもVisual C++が必要なわけでありません。ほかのC/C++コンパイラや開発ツールでも,Windowsアプリケーションの開発は可能です。 例えば,Borland C++Compilerなどのコマンドライン・コンパイラでも,Windowsアプリケーションを作れます。ただしその場合,イベント,メッセージ,メッセージ・キュー,ウィンドウ構造体,ウィンドウ・プロシジャなど,Windowsアプリケーション開発に必要な知識やテクニックを身に付ける必要があります。

そうした面倒な学習をすることなく,「自作のプログラムに手っ取り早くWindowsのGUIを持たせたい」という場合は,Visual StudioやBorland Delphiなどのマウス操作でフォームを作れる機能を持った開発ツールを使うのがいいでしょう。

Delphi は Delphi であって C/C++ ではないぞ。おぢさんびっくりだ。

まぁ Builder は使ったことないのでアレなんだが、VC の場合は MFC か .NET を使うことになるわけでしょ。やりたいことにもよるんだろうが、決して「マウス操作でフォームを作れる」からといって万事解決って言えるほど、簡単な代物ではないように思うのだが。。。

まぁ、たしかに SDK 叩いて全部 1 から組むのと、スケルトン生成してから組むのとでは、どっちが楽かっていえば、後者のほうが楽っちゃ楽なのだが。。。

ちなみに、VC++ 2005 Express でも、.NET Framework によるスケルトンは生成してくれるし、Platform SDK とセットで導入すれば従来のメッセージループベースによるウィンドウプログラム用のスケルトンも生成できるようになる。MFC は無いし、リソースエディタも無いから自分で RC スクリプト書かなきゃならないけど。

WideStudio は、後で試してみよう (個人的に、この記事唯一の収穫^-^;)。

Q12: C/C++でWebプログラミングってできるの?

きっとこの人はいわゆる「Webアプリ」のことを想定して書いているのだと思うのだが。。。Apache モジュールを開発するんであれば普通は C を使うし (mod_perl を使うって手もあるけどね)、そもそも Apache 自体が C で書かれている訳で (Firefox もな)。。。まぁこういう質問をする人がそもそもその辺まで考慮に入れて質問しているってこともあんまりないんだろうけど。

Q15: “Bjarne Stroustrup”ってどう読むの?

おいらも聴いてみた。「びやぁ~んぬしゅぽしゅぽ」って聴こえた…。これからは彼のことを「しゅぽしゅぽ博士」って呼ぶことにしよう。w

Q16: 仮想関数の「仮想」ってどういう意味?

そこまで説明するくらいなら実際にソースを書いて見せればいいのに。最初の段落だけで十分だよ。

Q18: NULLって何? どう読むの?

これも説明が回りくどい。以下を順序だてて簡潔に説明すべし。

  • C/C++ ではポインタ変数が「何も指さない」ことを示したい場合、明示的に 0 (数値のゼロ) を代入することになっている。
  • NULL は、上記の用途のために、0 (または ((void *)0)) をマクロ定義したものである。
  • NULLstdio.h などの中で定義されており、使用するにはこれらを #include する必要がある。

んなところかなぁ。

オリコンきめぇwwwwwwwwwwwww2006年12月19日 18時49分21秒

 :||:: \おい、烏賀陽弘道! 隠れても無駄だ ゴルァ!     ドッカン  ゴガギーン
 :|| ::   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄∨ ̄ ̄_m ドッカン     ☆
 :||::   ___     ======) ))_____ /        / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
 :||  |     |      | ̄.ミ∧_∧ | | ────┐||::    ∧_∧ < おらっ! 出て来い!! 烏賀陽弘道!!
 :||  |___|      |_..(   ) | | .___ │||::   (`Д´ )  \____________
 :||  |___|      |_「 ⌒ ̄  ,|.. |´・ω・`| :| ||::  / 「    \ ::.
 :||  |___|      |_| オ  ,/  ̄ .  ̄ ̄ ̄ │||::  | | オ  /\\
 :||:   ̄ ̄ ̄         ̄| リ  .| :||│     ;,   │||; へ//|リ |  |. |
 :||::   :;  ; ,,         :| コ  :.| ||│       (\/,.へ \|コ | ::( .)
 :||::   :;  冫、. .      | ン .i  .|:||◎ニニニニ\/  \  ン  |    ̄
 :||.:,,'';      ` ..  . ::  . |  ∧. |:||│::::/    │||::.:.   .Y ./ ..:: ;;
 :||:;;;:    ;;.. ::::: 冫、 : .:: .|  | | |.||│ 冫、 ;;;,,│||:;;;.   | .|  ........
 :||:;;;:  .....   .. `     / /  / /::||│ `  .,;;;,,.│||:;;;.   | .|  ...:L
 :||;::: #   ..:        ./ / ./ ./ ||│|三三三|. │||;;:..::   | .| . #.. :: ;;
 :||;:::     #. ..:  :::::: (_) .(_).ミ||│        │||;;;k、,,,|,(_).. ,,, :::
   ̄ ̄ ̄ ̄ ̄: ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
∥ドッカン
   ∧_∧                 ヽ∥    / へ
 (((´;ω;`)) 5000万円!!   -  ∥(ヽノ /
 (((つ旦と)) )               /∥ ヽノ
  ,,と_)_) ブルブル           ∥
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ 
     ↑烏賀陽氏

いやー、しかしオリコンの統計ってやっぱりというかなんというか、信憑性低いのね。やっぱり某 S の付くアレとかも捏zうわおまいら何をsくぁwせdrftgyふじこlp;@

テストデータの考え方。2006年12月19日 19時33分20秒

また、設計書をもらってコードを書く前に試験データを作成するのですが、一つの入力で複数のチェックが同時にできるような試験データを作成せずに、一つのデータでたった一つの項目のチェックをする試験データを作るようになりました。確かに、一つで複数の確認をできるデータの方が試験の効率も良いのですが、それは今試験をするには良いですが、試験の内容を他のメンバに説明するときや、後々試験項目を見直すことになったりした際に、試験データのすべての意図を読み取ることができずに、本当にこの試験データですべての試験すべき内容が満たされているかの確認ができないのです。

実は今、ちょうどこの部分で悩んでいて、効率的であることが良いという-過去の私と同じ考えを持っている-人に、どう伝えようか悩んでいたりします。少しずつは伝えているつもりですが、美しいという単語を使うのもなんだか恥ずかしくて、うまく伝えられていない気がしているのです。

いろんな利点が考えられる。。。というか、個人的には必須要件だとさえ思います。

  • 統計を取りやすくする為。テストの項目数=実施数=確認項目数とすることで、統計がシンプルになり、統計の品質が上がります。従って、QA における製品の品質管理がより精密になります。
  • テスト項目を整理しやすくする為。仕様変更時にはテストも再設計する必要がありますが、分類上の編成を組み替えるようなことが必要になる場合、一回の実施で複数の結果を求めるようなテストは、メンテナンスが困難になります。このことは、将来バージョンの品質維持が困難もしくは低下することを意味します。
  • テストの自動化システムの設計を容易にする為。テストツールは、あまり複雑なものにすべきではありません。テストツールにバグが混入するような自体は、絶対に避けなければなりません。

他にもありそうな気もしますが。。。とりあえず、こんなところでいかがでしょう?