intとint32_tとint64_tとsize_tのどれを使うか
問題
int, size_t はサイズが不明瞭
int は実装が最も取り扱いやすい整数型として定義されている。
数値リテラルは型を明示しなければ int 型
int は 64bit 環境でも 32bit 値 (ILP64 の時のみ64bit。Windows はLLP64, Linuxなどは LP64 →64ビット対応) size_t は 64bit 環境で 64bit だが、符号なしなので、int とで明示的なキャストが必要になっている。
int64_t は値を保存するのに8バイトも使用してしまう。
int32_t の倍になってしまう。
int32_t はたまに値域が足りない事がある。
2GB 以上のデータを扱うときに困る。
最近はメモリを16GBとか積んでいるので、足りない事がある。
動画データだと 2GB は余裕で超える事がある。
intmax_t はサイズが不明瞭。128bit になっている可能性がある。(常用するには大きすぎる。)
いずれかの型を使うと、それが「伝染」する。
関連するすべてがそれを一貫して使わなければならない。
ゆえに最初の定義が肝心となる。
int から int32_t, int64_t へのキャスト、および逆のキャスト(およびそのチェック)が必要となる。
sizeof(int32_t) == 4 は固定的か?
sizeof で返ってくるのは char 配列で保持するときに必要とされる配列の要素数。
CHAR_BIT != 8 の環境では違う可能性がある。
たまたま大半の実装が CHAR_BIT == 8 になっているので、それをみんなあてにしているが正しくない。
int32_t はそれより大きなサイズのレジスタに割り当てられる可能性がある。
int_fast32_t, int_least32_t のように複数の定義があるが「32bit の値を入れても問題がない変数」という定義でしかない。
値域を超えたときにラップアラウンドすることを期待したプログラムは正しく動かない可能性がある。 PRId32 などのマクロを含む文字列は、外部記憶(ファイルやデータベースなど)に入れられない。ハードコーディング専用になってしまう。
そもそもC言語の printf とデータ型設計が設計ミス。
「コードを書き換えなくても自動的に実装に適したサイズになる」という考え方が残念ながら正しくなかった。
64bit値を使うか32bit値を使うかは、アプリケーションの要件に依存するので固定する事は本質的に不可能。
方法論
ジェネリクス型のコードにする。
定義をマクロで書いて、どの型でも実装できるようにする。
頻度の高い型の実装のみ用意しておき、本当に必要になった時に型の異なる実装をコピペで作る。
Microsoft の TCHAR のように、汎用型を定義して、マクロ定義でどれを使うか切り替える。
マクロ定義により、CHAR型、*A 関数(ANSI用) と WCHAR型、*W関数 (UTF-16用)の2種類のどちらかが使われる。
これはややこしくなるだけなので避けたい。
期待する動作についてテストコードを書く。テストが通らない場合に対策をする。
インターフェースで決まっているサイズを引き継ぐ。
関連