C言語を語る

プログラマ歴30年のさんを招いて、C言語について語り合いました。


そもそも俺は Pascal から高級言語に入ってるんですよ。

へえ、そうだったんですね。

なもんで、C言語について未だにしっくりこない点があるんだよね。

第一は、文字列型が無い点。


あぁ、C言語は char の配列しかないですからね。

文字列操作用の +演算子とか =演算子がなく、strcat() とか strcpy() の関数を使わなければならないのが、最初は「何それ?」って感じだったね。

Pascal の文字列は上限 256文字でしたっけ?

そこは言語依存だね。

C言語で文字列を扱う処理についてソースコードレビューすると、いっつも「NULL終端は保証されてるか?」「文字数オーバーしないか」という点をチェックされる。もっと本質に注力したいのにね。

それは全くその通り。
「世の中のバグの 20% は strcpy() で起こる」なんて言われたりするからね。





あと、Pascal にはない予約語 return には戸惑ったね。Pascal なら関数名に渡せばいいんだよね。
returnに () を付けるか付けないかで宗教戦争があるし。俺は () は付けない派。

私も付けないです。

これが厄介なのは、return のスペルを間違えたときに、コンパイルエラーになってくれないんだよね。で、リンクの時に初めてエラーになる。これで一回失敗した時がある。

私は単純にタイプ量を増やしたくないので、() を付ける理由は無いと考えてます。





もう一つ、C言語には 2進数リテラルが無いんだよね。元々 OS 書くための言語なのに、これは根本的におかしいと思う。

C言語には 2進数リテラルはないけど 8進数リテラルはありますよね。
さんは 8進数リテラルって使ったことあるんですか?

8進数リテラルを使ってたのは俺より上の世代だね。俺の世代以降は16進数だね。
一回だけ、16進数リテラルで書いてたら先輩に「8進数に直せ」って言われたことある。

時代を感じますね。

8進数リテラルがあるから、010 って書いたら 10 じゃなくて 8 になるじゃないですか。8進数って今日では使わないし、むしろ罠として働いている感がある。
2010年代に登場した Rust や Swift では、0x が 16進、0o が 8進、0b が 2進、となっている。今はこれが一番いいと思います。





その昔の頃では、変数名 6文字までとかの制限があったのですか?

関数名は 8文字までという制限があったね。
当時は Unix のユーザー名にも 8文字制限があった。だから、長い名前の人は短縮したユーザー名にしないといけなかったんだよね(笑)。

今時の「関数名・変数名はあまり省略せずに名付けよ」というコーディングルールが適用できない世界ですね。

俺は sizeof(char) が 8ビットじゃない環境も知ってるからね。

本当ですか!? 話には聞くけど全く見たことがないので、言葉遊びのレベルかと思ってました。

まあ、現代では「sizeof(char) は 8ビット」と割り切って書いた方が良いプログラムになると思うけど。





ARMアーキテクチャでは char が unsigned char として定義されている。これはとんでもない落とし穴。

割と根本的な問題ですよね。文字コードというのは、数値演算できるべきなのか、それとも文字へマッピングするための単なるキーなのか、という。

それはそうだけど、他の既存環境に右へ倣えで良かったと思う。char に ASCII 代入してたら引き算したくなるもんだし。

int って書けば signed int のことなんだから、char も同様にすべき、ってのは正論ですけどね。





でも、char が signed なのか unsigned なのかが実装依存っていうのは、規格にそう書かれている。

他に、signed 整数型が 2の補数であることを規格は保証していない、はずなんですよね。
これのせいで、signed 整数がオーバーフローした時の動作が Undefined Behavior だったり、負数を >> シフトした時の挙動が環境依存だったり、色々面倒なんですよね。


なるほど。

加減算の回路のことを考えたら、2の補数以外はほぼありえないないわけで、そこは規格で固めといて欲しかったなぁ。

昔の KR の時代はある種の無法地帯で、その頃から引き継いだ仕様があるよね。C言語があって CPU がそれに合わせるんじゃなくて、C言語の方が CPU に合わせようとしてたというかね。

ANSI C ができたのが 1989年で、それ以降は規格というのが俄然重きを置かれるようになった。


私もJIS規格のページはブックマークに入れてます。時々見ますよ。

直訳調の読みにくい日本語だけどね(笑)。

確かに読みにくいですけど、正確なことを知りたい場合には、規格に当たるのがベストです。

俺がよく人に勧めてた本に「詳説 C言語」というのがある。
これはC言語規格とその説明が書かれている本で、本当に勉強になった。なぜC言語にこのような機能があるのか、なぜC言語がこのような文法になっているか、とかそういう視点で理解できるようになった。

学生時代に教授からよく「第一ソースを見たか?」「原著を当たれ」と言われたのを思い出しました。
やっぱりWikipediaとかブログ記事じゃ不十分で、原著を見ないとダメなんですよね。

その通り。
「今使ってるこのコンパイルで動いてる」よりも「言語規格から判断して正しい」の方が重い。つまり、言語規格を理解できていないと、いつまでたっても強くなれない。これは強調しておきたいね。





個人的にC言語に入れてほしい機能として、={}; での配列や構造体の定義時ゼロ初期化、があります。
C++だと ={}; でゼロ初期化できる。 C言語では ={0}; と 0 が必要なんだけど、これだと先頭要素が構造体だったりで 0 で初期化できない場合、コンパイルエラーになってしまう。

KR の時代にはそもそも変数定義と代入を同時にはできなかったんだよね。その頃からの慣習もあって、C言語では初期化代入が弱いままだよね。

うーん、でも互換性とかの問題はなさそうだし、C99以降でもいいから言語仕様として入れてほしかったなぁ。

あともう一つ、関数単位 or スコープ単位での at_exit() がほしかった。


それは確かに。
GCC拡張では関数に入る時と出る時に呼び出す関数というのを作れる。言語仕様に入っても良かったと思う。

0 件のコメント:

コメントを投稿