memmove, memmove_s
提供: cppreference.com
<tbody>
</tbody>
| ヘッダ <string.h> で定義
|
||
void* memmove( void* dest, const void* src, size_t count ); |
(1) | |
errno_t memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count); |
(2) | (C11以上) |
1)
src の指すオブジェクトから dest の指すオブジェクトに count 個の文字をコピーします。 どちらのオブジェクトも unsigned char の配列として再解釈されます。 オブジェクトはオーバーラップしても構いません。 コピーは、文字が一時的な文字配列にコピーされ、その後その配列から dest にコピーされたかのように、行われます。dest 配列の終端を超えてアクセスが発生する場合、動作は未定義です。 dest または src が無効またはヌルポインタの場合、動作は未定義です。2) (1) と同じですが、以下のエラーを実行時に検出した場合、 (
dest と destsz がどちらも有効であれば) コピー先の範囲 [dest, dest+destsz) 全体をゼロクリアし、現在設定されている制約ハンドラ関数を呼びます。
destまたはsrcがヌルポインタ。destszまたはcountが RSIZE_MAX より大きい。countがdestszより大きい (バッファオーバーフローが発生する)。
dest の指す文字配列のサイズ < count <= destsz の場合、動作は未定義です。 別の言葉で言うと、誤った destsz の値は切迫したバッファオーバーフローを露呈しません。
- すべての境界チェック付き関数と同様に、
memmove_sは__STDC_LIB_EXT1__が処理系によって定義されていて、<string.h>をインクルードする前にユーザが__STDC_WANT_LIB_EXT1__を整数定数 1 に定義した場合にのみ、利用可能であることが保証されます。
引数
| dest | - | コピー先のオブジェクトを指すポインタ |
| destsz | - | コピー先の変更する最大バイト数 (一般的にはコピー先オブジェクトのサイズ) |
| src | - | コピー元のオブジェクトを指すポインタ |
| count | - | コピーするバイト数 |
戻り値
1)
dest のコピーを返します。2) 成功した場合はゼロ、エラーが発生した場合は非ゼロの値を返します。 また、エラーの場合、
dest がヌルポインタでなく destsz が有効であれば、 destsz 個のゼロのバイトをコピー先の配列に書き込みます。ノート
memmove は確保関数で取得したオブジェクトの実効型を設定するために使用することができます。
一時的なバッファを使用する「かのように」と規定されているにもかかわらず、この関数の実際の実装は二回のコピーや余分なメモリのオーバーヘッドを負担しません。 一般的な手法 (glibc および bsd libc) は、コピー先がコピー元より前に始まるならばバッファの先頭から順方向に、そうでなければ末尾から逆方向にバイトをコピーし、オーバーラップがまったくないときは memcpy にフォールバックします。
厳格なエイリアシングにより同じメモリを2つの異なる型の値として調べることが禁止される場合に、値を変換するために memmove を使用することができます。
例
Run this code
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char str[] = "1234567890";
puts(str);
memmove(str+4, str+3, 3); // copy from [4,5,6] to [5,6,7]
puts(str);
// setting effective type of allocated memory to be int
int *p = malloc(3*sizeof(int)); // allocated memory has no effective type
int arr[3] = {1,2,3};
memmove(p,arr,3*sizeof(int)); // allocated memory now has an effective type
// reinterpreting data
double d = 0.1;
// int64_t n = *(int64_t*)(&d); // strict aliasing violation
int64_t n;
memmove(&n, &d, sizeof d); // OK
printf("%a is %" PRIx64 " as an int64_t\n", d, n);
#ifdef __STDC_LIB_EXT1__
set_constraint_handler_s(ignore_handler_s);
char src[] = "aaaaaaaaaa";
char dst[] = "xyxyxyxyxy";
int r = memmove_s(dst,sizeof dst,src,5);
printf("dst = \"%s\", r = %d\n", dst,r);
r = memmove_s(dst,5,src,10); // count is greater than destsz
printf("dst = \"");
for(size_t ndx=0; ndx<sizeof dst; ++ndx) {
char c = dst[ndx];
c ? printf("%c", c) : printf("\\0");
}
printf("\", r = %d\n", r);
#endif
}
出力例:
1234567890
1234456890
0x1.999999999999ap-4 is 3fb999999999999a as an int64_t
dst = "aaaaayxyxy", r = 0
dst = "\0\0\0\0\0yxyxy", r = 22
参考文献
- C11 standard (ISO/IEC 9899:2011):
- 7.24.2.2 The memmove function (p: 363)
- K.3.7.1.2 The memmove_s function (p: 615)
- C99 standard (ISO/IEC 9899:1999):
- 7.21.2.2 The memmove function (p: 326)
- C89/C90 standard (ISO/IEC 9899:1990):
- 4.11.2.2 The memmove function
関連項目
(C11) |
バッファを別のバッファへコピーします (関数) |
(C95)(C11) |
2つのオーバーラップしている可能性のある配列間でワイド文字を一定量コピーします (関数) |
memmove の C++リファレンス
| |