それ、C関係ないのでは

ずいぶん前の記事に反応しますが。

Cはワンマン向け - 神様なんて信じない僕らのために

■[misc]Cはワンマン向けだと考えるようになった。

いや、あくまで自分の中ではです。

今、Cで作られたものを参考にしてC++に移す作業をしていたりするんだけれども、

至る所に出現する、

void*
コールバック
謎フラグ
hoge->foo->bar->ptr

Cが、他の言語(JavaとかC#とか?)に比べてとにかくもう圧倒的にダメなところは、

  • 実行時のチェックがない。よって、配列のオーバーラン、不正なキャスト、開放されたメモリを参照する、といった理由でのバグが発生し、原因追及が非常に困難。
  • GCがない。

の2点でしょう(特に前者)。C++ではこの2点(特に前者)については、書き方次第でマシになるとはいえ、完全に解決されてはいません。

で、Isoparametricさんの言うところの問題点ですが、

void*

void*は至る所で何かに化ける。

まあそのとおりですが、これはJavaとかでObjectを使っても同じことですね。Genericsなりtemplateなりを使えば別ですが。
C++なら、かなり前からtemplateはあったので、C++ユーザのIsoparametricさんがここに不満を持つのはまあわからなくはないです。
Cに固有の問題と言うなら、むしろchar*で好き勝手なメモリアクセスを行うプログラムじゃないかなあ。

コールバック

StateやStrategy風なことをしようとしてコールバックの嵐になるんだけれども、
あっちやそっちやこっちに飛んだりして遷移が読みづらい。

StateやStrategy風なことをしようとするCプログラマって、相当に意識が高い人のように思います。まあ、結果としてプログラムが読みにくくなっては意味がないのですが。
それはさておき、C#delegateなんて関数ポインタそのものだし、実行時に動きを変えたくてinterfaceをぶっ挿したりポリモルフィズムを使うなんてことはむしろOO言語の方がよくやること、そして、「あっちやそっちやこっちに飛んだりして遷移が読みづらい」のは、これらの方法でも同様に発生することです。

大昔、こんなの↓を書きましたが、
新プログラミング言語「BF-BASIC'n」

あまつさえ、OO言語では、ポリモルフィズムという機能により適用される手続きすら実行時に決まるのですから、プログラムのソースを読むこと(静的な解析)はますます困難になってしまっています。 Cなどでは、ある関数のソースを読む際、目的の関数からどんどん下位へと掘り進めていけばいいわけですが、 OO言語では、インスタンスフィールドなどに保持されているオブジェクトのメソッドが呼ばれていたら、そのオブジェクトが生成されているところまで遡って読む必要があります。しかし、ソースを遡って読む、つまり、どの実行パスを通ってそこに来たかを探ることは、単に実行順で読んでいくのに比べて圧倒的に難しいものですし、それどころか、やっと探り当てたオブジェクトの生成箇所で デザインパターンなんぞ使われていたりすると、さらにそこから長い旅の始まりです。

エイプリルフールネタとはいえ、上記記述自体はそれなりに真実だと思います。もちろん、だからOOが悪いというのではなく、静的にソースを追うことが難しくなる代わりに柔軟性を得ているのですが。

謎フラグ

至るところにあるhoge_flag & HOGE_FOO_BAR、
フラグの名前だけでは何をしているのかわからないよ……。orz
isHogeとかcanHogeとかhasHogeとかならわかるんだけど、
すべて&や|や~でやられるとわからん。

名前の問題? それともビット演算の問題?

名前の問題ならC関係なくて書いたプログラマの問題だし、ビット演算がわからないのはIsoparametricさんの問題なのでは。

hoge->foo->bar->ptr

指している先がわかるためにはすべて追っていかないとわからない。

C++だろうがJavaだろうがC#だろうが、これについては事情はまったく同じでは? (「->」ではなく「.」ならいいって問題でもないでしょう)

# Cの場合、ポインタのキャストや間接演算子(*)を使われると、前置なので戻って
# 読まなければならない上に無駄な括弧が出てくる、という不都合はあります。
# でも、出ている例はそういう例じゃないしなあ。