C の文字列処理

現実逃避がまた。

■[SWE]ありがちなバグ

という記事で、

そのコードを見せてもらった。

    static char hoge1[2] = "ER";
    static char hoge2[6] = "000000";

で、hoge1 や hoge2 はあちこちで定数的に使われているそうだ。これじゃ期待通りに動くわけないよなぁ。

と書かれていました。
なるほど、ぱっと見て以下の様な問題がある様に見受けられます。

  1. 終端文字が切り捨てられている。
  2. 定数的に使われている (定数*的*というところが引っ掛りますが……) にも係わらず書き換え可能。
  3. そもそもマクロ使いませんか? そうでなくてもポインタ変数ですかね。

satoshis さんがどの様に思っておられるかは判らないのですが、私が思った問題としては、上記の様なところでしょうか。実は全然見当違いなのかもしれませんが。

見当違いなのかもしれないんですが、私は特に 1. の問題が、C の文字列処理の微妙な問題になっていると思っています。

C 言語では、文字列を char 型の変数の配列として扱い、その際に重要な役割を果たすのが、この終端文字 (空文字) です。
C で文字列処理を行なう場合、標準ライブラリの多くが、この終端文字を文字列の終端として扱う約束事の上に成り立っているので、これを正しく操作しなければいけないというのが共通認識ですよね。

しかし、昨今の secure programming な観点からすると、この終端文字に頼った code は問題が発生し易いため、文字列の長さを正しく認識、操作する code が推奨されていると思います。buffer overflow を回避するためのもので、境界を意識して操作することが求められていることだと認識しています。
いきおい、strcpy(3) でなく strncpy(3)、果ては strlcpy(3) を使えという具合ですね。

その様な観点から見ると、あながち、終端文字を含まない配列の定義もあり得るのかもしれません。ただ、その様な配列を素のまま操作することは、その文字列長を正しく対応させることが煩雑で難しくなるため、アクセサを用意してやらなければならなくなるとは思いますが。
また、他言語、他システムとのデータ交換に伴なうインタフェースを考える場合も、終端文字で文字列の境界を決定する枠組みに頼り過ぎると問題があるでしょう。まあ、通常は、きちんとプロトコルやインタフェースを定めて実装するので、その中で解決される問題だとは思いますが。

あと、マクロを使うかというところは、多分に設計者、実装者の趣味の問題に係わるのかもしれませんが、static char[] などとする場合はシンボルテーブルに登録されることになる筈なので、Binary 2.0 な人には色々と役立つのかもしれません。