web-dev-qa-db-ja.com

Cの配列インデックスの正しいタイプは何ですか?

C99の配列インデックスにはどのタイプを使用する必要がありますか? LP32、ILP32、ILP64、LP64、LLP64などで動作する必要があります。 C89タイプである必要はありません。

5つの候補者を見つけました。

  • size_t
  • ptrdiff_t
  • intptr_t/uintptr_t
  • int_fast*_t/uint_fast*_t
  • int_least*_t/uint_least*_t

問題をよりよく説明するための単純なコードがあります。これらの2つの特定のループにおけるijの最適なタイプは何ですか。正当な理由がある場合は、2つの異なるタイプでも問題ありません。

for (i=0; i<imax; i++) {
        do_something(a[i]);
}
/* jmin can be less than 0 */
for (j=jmin; j<jmax; j++) {
        do_something(a[j]);
}

追伸質問の最初のバージョンでは、負のインデックスについて忘れていました。

P.P.S. C99コンパイラを書くつもりはありません。しかし、コンパイラープログラマーからの回答は私にとって非常に価値があります。

同様の質問:

41
Michas

次の理由で_ptrdiff_t_を使用する必要があると思います

  • 指数は負の場合があります。したがって、一般的なステートメントでは、_size_t_を含むすべての符号なし型は不適切です。
  • _p2 - p1_の型は_ptrdiff_t_です。 _i == p2 - p1_の場合、_p2_によって_p2 == p1 + i_を取り戻すことができるはずです。 *(p + i)は_p[i]_と同等であることに注意してください。
  • この「一般的なインデックスタイプ」の別の指標として、組み込みの_operator[]_(ポインタなど)がユーザー提供の_operator[]_(forベクトルの例)はまさにそれです( http://eel.is/c++draft/over.built#16 ):>

    すべてのcv修飾またはcv非修飾オブジェクトタイプTには、次の形式の候補演算子関数が存在します。

    _T*      operator+(T*, std::ptrdiff_t);
    T&      operator[](T*, std::ptrdiff_t);
    T*      operator-(T*, std::ptrdiff_t);
    T*      operator+(std::ptrdiff_t, T*);
    T&      operator[](std::ptrdiff_t, T*);
    _

編集:本当に大きな配列または本当に大きなメモリ部分へのポインタがある場合、私の「一般的なインデックスタイプ」はそれをカットしません、その場合、最後の要素のアドレスから最初の要素のアドレスを減算できることが保証されないためです。 @Ciroの回答を使用する必要があります https://stackoverflow.com/a/31090426/34509 。個人的には、負のEdgeケース(たとえば、逆方向に反復するときのループの終了値)を表すことができないため、符号なしの型を使用しないようにしていますが、これは一種の宗教的な議論です(私はそのキャンプで一人ではありません) 。符号なしのタイプを使用する必要がある場合は、もちろん、私の宗教を脇に置く必要があります。