84

私はC標準に精通していないので、ご容赦ください。

memcpy(0,0,0)安全であることが標準で保証されているかどうかを知りたいです。

私が見つけた唯一の制限は、メモリ領域が重複している場合、動作が未定義であることです...

しかし、ここでメモリ領域が重複していると考えてよいでしょうか?

4

4 に答える 4

73

私は C 標準 (ISO/IEC 9899:1999) のドラフト版を持っていますが、その呼び出しについて興味深いことがいくつかあります。まず、それに関して (§7.21.1/2) に言及していますmemcpy

nとして宣言された引数がsize_t関数の配列の長さを指定する場合、n はその関数の呼び出しで値 0 を持つことができます。7.1.4 で説明されているように、この節の特定の関数の説明で明示的に別の方法で述べられていない限り、そのような呼び出しのポインター引数は引き続き有効な値を持つものとします。このような呼び出しでは、文字を検索する関数はオカレンスを検出せず、2 つの文字シーケンスを比較する関数は 0 を返し、文字をコピーする関数は 0 文字をコピーします。

ここに示されている参照は、次のことを示しています。

関数の引数に無効な値 (関数のドメイン外の値、プログラムのアドレス空間外の ポインター、null ポインター、または対応するパラメーターが変更できないストレージへのポインターなど) がある場合が const 修飾されていない)、または可変数の引数を持つ関数で予期されていない型 (昇格後) の場合、動作は undefinedです。

したがって、C仕様によると、呼び出しのように見えます

memcpy(0, 0, 0)

null ポインターは「無効な値」と見なされるため、未定義の動作が発生します。

memcpyそうは言っても、あなたがこれを行った場合、 の実際の実装が壊れていたら、私はまったく驚かされるでしょう。

于 2011-03-09T08:24:36.010 に答える
24

楽しみのために、gcc-4.9 のリリース ノートでは、オプティマイザがこれらのルールを使用しており、たとえば、条件を削除できることが示されています。

int copy (int* dest, int* src, size_t nbytes) {
    memmove (dest, src, nbytes);
    if (src != NULL)
        return *src;
    return 0;
}

copy(0,0,0)が呼び出されたときに予期しない結果が得られます ( https://gcc.gnu.org/gcc-4.9/porting_to.htmlを参照)。

私は、gcc-4.9 の動作についてやや曖昧です。動作は標準に準拠している可能性がありますが、 memmove(0,0,0) を呼び出すことができることは、これらの標準の拡張に役立つ場合があります。

于 2014-07-12T05:32:12.423 に答える