memmove, memmove_s
From cppreference.net
|
定義先ヘッダ
<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
が無効なポインタまたはnullポインタである場合も、動作は未定義です。
2)
(1)
と同様ですが、実行時に以下のエラーを検出した場合、宛先範囲全体
[
dest, dest
+
destsz
)
をゼロクリアし(
dest
と
destsz
の両方が有効な場合)、現在設定されている
constraint handler
関数を呼び出します:
-
- dest または src がnullポインタの場合
- destsz または count が RSIZE_MAX より大きい場合
- count が destsz より大きい場合(バッファオーバーフローが発生する)
destが指す文字配列のサイズが
dest
<
count
<=
destsz
の場合、動作は未定義である。言い換えれば、
destsz
の誤った値は、差し迫ったバッファオーバーフローを露呈しない。
-
すべての境界チェック付き関数と同様に、
memmove_sは、実装によって __STDC_LIB_EXT1__ が定義され、かつユーザーが <string.h> をインクルードする前に __STDC_WANT_LIB_EXT1__ を整数定数 1 に定義した場合にのみ利用可能であることが保証される。
目次 |
パラメータ
| dest | - | コピー先オブジェクトへのポインタ |
| destsz | - | コピー先で変更可能な最大バイト数(通常はコピー先オブジェクトのサイズ) |
| src | - | コピー元オブジェクトへのポインタ |
| count | - | コピーするバイト数 |
戻り値
1)
dest
のコピーを返す
2)
成功時はゼロを返し、エラー時は非ゼロの値を返す。またエラー時、
dest
がnullポインタでなく、
destsz
が有効な場合、
destsz
バイトのゼロを宛先配列に書き込む。
注記
memmove
は、割り当て関数によって取得されたオブジェクトの
effective type
を設定するために使用されることがあります。
一時バッファが使用される「かのように」仕様が定められているにもかかわらず、この関数の実際の実装では、オーバーヘッドや二重コピー、余分なメモリ消費は発生しません。一般的なアプローチ(glibcおよびbsd libc)では、宛先がソースより前に始まる場合はバッファの先頭から順方向にバイトをコピーし、それ以外の場合は末尾から逆方向にコピーします。また、オーバーラップが全くない場合には、より効率的な memcpy にフォールバックします。
strict aliasing
が同じメモリを異なる2つの型の値として検査することを禁止する場合、
memmove
を使用して値を変換することができます。
例
このコードを実行
#define __STDC_WANT_LIB_EXT1__ 1 #include <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char str[] = "1234567890"; puts(str); memmove(str + 4, str + 3, 3); // [4,5,6] から [5,6,7] へコピー puts(str); // 割り当てられたメモリの実効型を int に設定 int* p = malloc(3 * sizeof(int)); // 割り当てられたメモリには実効型がない int arr[3] = {1, 2, 3}; memmove(p, arr, 3 * sizeof(int)); // 割り当てられたメモリに実効型が設定された // データの再解釈 double d = 0.1; // int64_t n = *(int64_t*)(&d); // 厳格なエイリアシング違反 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 が 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
参考文献
- C23規格 (ISO/IEC 9899:2024):
-
- 7.24.2.2 memmove関数 (p: TBD)
-
- K.3.7.1.2 memmove_s関数 (p: TBD)
- C17規格 (ISO/IEC 9899:2018):
-
- 7.24.2.2 memmove関数 (p: 264)
-
- K.3.7.1.2 memmove_s関数 (p: 446)
- C11規格 (ISO/IEC 9899:2011):
-
- 7.24.2.2 memmove関数 (p: 363)
-
- K.3.7.1.2 memmove_s関数 (p: 615)
- C99規格 (ISO/IEC 9899:1999):
-
- 7.21.2.2 memmove関数 (p: 326)
- C89/C90標準 (ISO/IEC 9899:1990):
-
- 4.11.2.2 memmove関数
関連項目
|
(C11)
|
バッファを別のバッファにコピーする
(関数) |
|
(C95)
(C11)
|
2つの配列間(重複する可能性あり)で指定された量のワイド文字をコピーする
(関数) |
|
C++ documentation
for
memmove
|
|