13

次のコードがあるとします。

char buffer[1024];
char * const begin = buffer;
char * const end = buffer + 1024;
char *p = begin + 2000;
if (p < begin || p > end)
    std::cout << "pointer is out of range\n";

実行された比較 (p < beginおよびp > end) は明確に定義されていますか? それとも、ポインターが配列の末尾を超えて進められているため、このコードの動作は未定義ですか?

比較が明確に定義されている場合、その定義は何ですか?

(追加のクレジット:begin + 2000それ自体の評価は未定義の動作ですか?)

4

3 に答える 3

10

C++11標準を想定します。セクション 5.7 (Additive Operands) の段落 5 によると、 の動作*p = begin + 2000は最初に未定義であり、比較する前に次のようになります。

ポインターオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は未定義です。

于 2012-12-21T21:10:39.177 に答える
6

の評価begin+2000は未定義です。配列の末尾を超えています。末尾を 1 つ超えることはできますが、それ以上はできません。

C++11 §5.7/5加法演算子から:

整数型の式をポインターに加算またはポインターから減算すると、結果はポインター オペランドの型になります。ポインターオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、結果は元の要素からオフセットされた要素を指し、結果と元の配列要素の添え字の差が整数式に等しくなります。[...] ポインター オペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は undefinedです。

ポインター比較を指定するには、最初に有効なポインターがあると仮定すると、それらは基本的に同じ配列 (または最後の 1 つ後) へのポインター、または同じアクセス制御の非静的データ メンバーへのポインターである必要があります。オブジェクト(ユニオンでない限り...)。

詳細は§5.9/2関係演算子にあります:

同じ型 (ポインター変換後) のオブジェクトまたは関数へのポインターは、次のように定義された結果と比較できます。

  • 同じ型の 2 つのポインター p と q が同じオブジェクトまたは関数を指している場合、または両方が同じ配列の末尾の 1 つ後ろを指している場合、または両方が null の場合、p<=q と p>=q の両方が true と p を返します。 <q と p>q は両方とも false になります。
  • 同じ型の 2 つのポインター p と q が、同じオブジェクトのメンバーではない、同じ配列の要素ではない異なるオブジェクト、または異なる関数を指している場合、またはそれらの 1 つだけが null である場合、p<q, p の結果>q、p<=q、および p>=q は指定されていません。
  • 2 つのポインターが同じオブジェクトの非静的データ メンバー、またはそのようなメンバーのサブオブジェクトまたは配列要素を再帰的に指す場合、後で宣言されたメンバーへのポインターは、2 つのメンバーが同じアクセス制御 (条項 11) を持ち、かつクラスが共用体でない場合。
  • 2 つのポインターが、異なるアクセス制御 (第 11 節) を持つ同じオブジェクトの非静的データ メンバーを指している場合、結果は規定されていません。— 2 つのポインターが同じユニオン オブジェクトの非静的データ メンバーを指している場合、それらは等しいと比較されます (必要に応じて void* への変換後)。2 つのポインターが同じ配列の要素を指している場合、または配列の末尾を超えた 1 つの要素を指している場合、添字の大きい方のオブジェクトへのポインターが比較されます。
  • その他のポインター比較は指定されていません。
于 2012-12-21T21:09:13.873 に答える
3

プログラムの動作は未定義ですが、比較のためではありません。

begin + 2000結果が 1024 要素の配列の末尾を超えて複数の要素を指すため、式の評価の動作は未定義です。

C++11 (実際にはN3485ドラフト)、5.7p4 [expr.add] を引用:

整数型の式をポインターに加算またはポインターから減算すると、結果はポインター オペランドの型になります。[...] ポインター オペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は未定義です。

つまり、範囲外のポインターを計算するだけでは、未定義の動作になります。その後、そのポインターに対してどのような操作を実行してもかまいません。

于 2012-12-21T22:39:50.627 に答える