大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

Javaでナル終端文字列

株式会社クローバーフィールドの経営理念
著者:高木信尚
公開日:2014/05/05
最終更新日:2018/06/12
カテゴリー:雑記
タグ:

こんにちは、スタッフの高木です。今回も技術情報ですが、私としては素人に毛の生えた程度のスキルしかないJavaに関する内容です。

ナル終端文字列というのは、文字列の長さを直接管理するのではなく、ナル文字を入れることで文字列の終端を指示する形式の文字列データです。これは主にCで使われる文字列の形式で、Javaの標準的な文字列とは異なります。

しかし、ファイルや通信などでバイナリデータを扱う場合には、Cの流儀のナル終端文字列を扱わなければならないこともあります。その都度自分でロジックを書いたり、Javaの標準的なメソッドを組み合わせて実現することもできるでしょうが、C互換の静的メソッドを用意しておくと何かと便利です。

メソッドのシグニチャに関しては、何もCの流儀に従う必要はありませんので、Javaらしいメソッド名を付けてもよいですし、引数のとり方も好みに合わせればよいかと思います。しかし、ナル終端文字列を扱うようなケースでは、もともとCのコードがあって、それをポーティングするか、それに近い状況が多いのではないでしょうか? それであれば、C互換のメソッドを用意しておけばそれなりにメリットがあります。

Cにはナル終端文字列を操作する関数が結構な数あるのですが、今回はそのうちの代表的なものとして、strlen, strcpy, strcat, strcmpを実装することにします。

Java版のナル終端文字列操作メソッドを実装するにあたり、CのポインタをJavaでどう表現するかを決めなければなりません。単にポインタと同じことを表現できるというだけでなく、想定用途であるファイルや通信におけるバイナリファイルの扱いにおける利便性も合わせて考えなければなりません。

私のつたないJavaの知識をもとに検討した結果、java.nio.ByteBufferを使うのが一番よいのではないかという結論に至りました。ByteBufferであれば、文字列が格納される実際のメモリ領域と文字列の開始位置を同時に表現することができるからで、これができればポインタの代替手段としても十分です。

それでは順に実装していきましょう。まずはstrlenです。このメソッドは、文字列の先頭から順に1文字1文字を調べ、ナル文字を探します。そして、ナル文字を含まない文字列の長さを返します。

もし、リミットまでにナル文字が現れない場合、このメソッドはIndexOutOfBoundsExceptionを投げることになります。Cの場合は、配列の範囲を超えた位置を指すポインタ経由でデータアクセスしようとした場合の動作は未定義ですので、それよりは安全といえるでしょう。

ByteBufferを使う上で気を遣うのは、内容を参照するだけのオブジェクトの状態を破壊しないようにすることです。strlenのような文字列の長さを調べたいだけのメソッドで、バッファの現在位置が変化してしまうのは我慢ならないでしょう。

次に実装するのはstrcpyです。このメソッドは文字列を終端のナル文字を含めて別のバッファにコピーします。

このメソッドでは、s2のリミットまでにナル文字が現れない場合、BufferUnderflowExceptionが投げられます。また、s1のリミットを超えて書き込もうとした場合、BufferOverflowExceptionが投げられます。strlenのときと例外の種類が異なりますが、まあ、これに関しては目をつぶることにしましょう。

次はstrcatの実装です。このメソッドは既存の文字列に別の文字列を連結します。連結すると行っても、バッファを再確保するわけではありませんので、バッファに十分なサイズがあることを呼び出し側で保証しなければなりません。

strcatでは、まずstrlenを使って元の文字列の長さを調べます。そして、その直後、すなわち、もとの文字列のナル文字の位置以降に別の文字列をコピーします。

このメソッドもstrcpyと同様、s2のリミットまでにナル文字が現れない場合、BufferUnderflowExceptionが投げら、s1のリミットを超えて書き込もうとした場合、BufferOverflowExceptionが投げられます。しかし、元の文字列にナル文字が見つからない場合は、strlen同様、IndexOutOfBoundsExceptionが投げられます。

これにより、何が原因で例外が発生したのかが、メソッドの内部をステップ実行するようなことをしなくても明確に判別することができます。

最後に実装するのはstrcmpです。このメソッドは、s1とs2の二つのナル終端文字列を比較し、s1の方が大きければ(つまり順序づけを行った際に後になるのであれば)プラスの値を、s1の方が小さければマイナスの値を、等しければ0を返します。

各文字列のリミットまでにナル文字が現れず、かつ大小関係も判別できなければ、BufferUnderflowExceptionを投げることになります。

一点注意しないといけないのは、オリジナルのCのstrcmpでは、各文字をunsigned char型として比較することが国際規格で定められています。ですので、同じ結果を得るためには、Javaの場合もbyte型の値をそのまま比較するのではなく、0xffでANDする必要があるということです。

今回実装したメソッドはすべて静的メソッドですので、適当なクラスを用意して、そのメンバとすればよいでしょう。使用に際しては、staticインポートしておけばCの関数とほぼ同様に使うことができます。ByteBufferの引数を用意するのは一手間かもしれませんが、それは本質的な問題ではないでしょう。

コメントは受け付けていません。

上に戻る