18

なんらかの理由で、 のゼロ化バージョンを手動でロールしたいと考えていmalloc()ます。アルゴリズムの複雑さを最小限に抑えるために、次のように記述します。

void * my_calloc(size_t size)
{
    return memset(malloc(size), 0, size);
}

これはいつ明確に定義されていsize == 0ますか? サイズ 0で呼び出しmalloc()ても問題ありませんが、これにより null ポインターが返される可能性があります。の後続の呼び出しはmemset問題ありませんか、それとも未定義の動作であり、条件を追加する必要がありますif (size)か?

冗長な条件チェックを避けたいと思います!

malloc()今のところ、失敗しないと仮定してください。実際にはmalloc()、失敗すると終了する手巻きバージョンもあります。

このようなもの:

void * my_malloc(size_t size)
{
    void * const p = malloc(size);
    if (p || 0 == size) return p;
    terminate();
}

4

3 に答える 3

10

glibc 宣言は次のとおりです。

extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));

__nonnull、ポインターが null でないことを期待していることを示しています。

于 2011-12-21T22:15:02.550 に答える
8

これについて、C99 標準は次のように述べています。

7.1.4 「ライブラリ関数の利用」

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

memset()7.21.1 「文字列関数の規則」 ( にある ことを思い出してくださいstring.h)

as として宣言された引数がsize_t n関数の配列の長さを指定するn場合、その関数の呼び出しで値 0 を持つことができます。この節の特定の関数の説明で明示的に別段の記載がない限り、7.1.4 で説明されているように、そのような呼び出しのポインター引数は引き続き有効な値を持つものとします。

7.21.6.1 「memset 関数」

このmemset関数は、c(に変換された) の値を、 が指すオブジェクトunsigned charの最初の各文字にコピーします。ns

厳密に言えば、標準ではsはオブジェクトを指さなければならないと規定されているため、null ポインターを渡すと UB になります。チェックを追加します (に比べてコストはmalloc()非常に小さくなります)。一方、malloc()が失敗しないことがわかっている場合 (終了するカスタム があるため)、 を呼び出す前にチェックを実行する必要がないことは明らかですmemset()

于 2011-12-22T20:39:26.697 に答える
7

再編集:

malloc()後でこれを追加しました:決して失敗しないと仮定してください。問題は、サイズが 0 になるかどうかだけです

分かりました。したがって、ポインターが nullでサイズが 0 の場合にのみ、物事を安全にする必要があります。

POSIX ドキュメントの参照

いいえ、null ポインターを使用して安全に呼び出すことが指定されていませんmemset(ゼロ カウントまたはサイズで呼び出した場合...それはさらに「興味深い」ですが、指定されていません)。

それについては、「有益な」セクションでも言及されていません。

最初のリンクが言及していることに注意してください

このリファレンス ページで説明されている機能は、ISO C 標準に準拠しています。ここで説明する要件と ISO C 標準との間の矛盾は、意図的なものではありません。このボリュームの IEEE Std 1003.1-2001 は、ISO C 標準に準拠しています。

更新ISO C99 標準 (n1256.pdf) は、POSIX ドキュメントおよびC++11 仕様と同様に簡潔であり、ANSI C 標準を参照しているだけであることを確認できmemsetます。N1256 は次のように述べています。

このmemset関数は、c(に変換された) の値を、 が指すオブジェクトunsigned charの最初の各文字にコピーします。ns

が nullである状況については何も述べてsいません (ただし、null ポインターはobjectを指していないことに注意してください)。

于 2011-12-21T22:09:46.123 に答える