11
char *buf = malloc(bufsize)
char *ptr = buf;
…
while(condition) {
    ptrdiff_t offset = ptr - buf;    // <========== THIS LINE

    // offset will never be negative because we only ever *increase* ptr
    if ((size_t)offset > bufsize) {
        // we need more room
        bufsize += 128;
        buf = realloc(buf, bufsize);
        ptr = buf + offset;  // buf might be in a completely new location
    }
    *ptr++ = …  // write this byte
}

これは有効ですか、それとも未定義ですか?

私はそれが有効であると想定していたでしょうが、未定義であると何かを読んだので、グーグルで調べました。これらのリンクは、未定義であると必然的に主張しているようです。

ただし、これらの SO の質問では言及されていません。

これらはすべて、同じ「配列」にある2つのポインターではないことを示しています。それは実際にスタック上の単純な古い C 配列を意味しますか?

定義されていない場合、私には非常に奇妙に思えます... 1 つの定数ポインターと 1 つの移動ポインターにアクセスできるのに、どうして強制的にカウンター変数を持ち歩かなければならないのでしょうか?

4

3 に答える 3

6

malloc同じ配列内にあるものとして countによって返されるメモリ ブロックへのポインター:

7.22.3 メモリ管理機能

1 - 割り当てが成功した場合に [から] 返さmallocれたポインタ [...] は、任意のタイプのオブジェクトへのポインタに割り当てられ [...]、空間内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されます割り当てられます (スペースが明示的に割り当て解除されるまで)。

于 2012-08-23T20:50:47.210 に答える
2
ptrdiff_t offset = ptr - buf;    // <========== THIS LINE

これは完全に定義された動作です。

(C99, 6.5.6p9) 「2 つのポインターが減算されると、両方とも同じ配列オブジェクトの要素を指すものとします [...]」

于 2012-08-23T20:55:23.157 に答える
1

配列の末尾を 1 要素以上超えない限り、定義済みの動作です。C99 §6.5.6/8 は、ポインターと整数の追加について次のように述べています。

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

そしてパラグラフ9、減算について:

9) 2 つのポインターが減算される場合、両方が同じ配列オブジェクトの要素を指すか、配列オブジェクトの最後の要素の 1 つ後ろを指します。[...]

そして§7.20.3/1から:

割り当てが成功した場合に返されるポインターは、任意の型のオブジェクトへのポインターに割り当てられ、割り当てられた空間内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスするために使用されるように適切に整列されます (空間が明示的に割り当て解除されるまで)。 .

ptrしたがって、最後の配列要素の後の要素を超えてポイントに移動すると、ポインターの減算を行うと未定義の動作になります。

名前は言えませんが、このコードでうまく動作しないシステムが世の中にあると私は信じています。理論的にmalloc()は、アドレス指定可能なメモリの末尾の直前にポインタを返すことができます。たとえば、255 バイトを要求すると、32 ビット システムでは 0xFFFFFF00 が返される可能性があるため、末尾を超えてポインタを作成するとオーバーフローが発生します。また、ポインター表現の整数オーバーフローが何らかのトラップをトリガーする可能性もあります (たとえば、ポインターが特殊なレジスターに格納されている場合)。これらの特性を持つシステムを私は知りませんが、C 標準では確かにそれらの存在が認められています。

于 2012-08-23T21:12:50.437 に答える