memcpy, memcpy_s
ja.cppreference.net より
| ヘッダ <string.h>
|
||
void* memcpy( void* dest, const void* src, size_t count );
|
で定義 (1) | (C99 まで) |
void* memcpy( void* restrict dest, const void* restrict src, size_t count );
|
(C99 以降) | |
errno_t memcpy_s( void* restrict dest, rsize_t destsz,
const void* restrict src, rsize_t count );
|
(2) | (C11 以降) |
1)
count 文字を、src が指すオブジェクトから dest が指すオブジェクトにコピーします。両方のオブジェクトは unsigned char の配列として解釈されます。dest 配列の終端を超えてアクセスが行われた場合の動作は未定義です。オブジェクトが重複している場合 (これは restrict 契約に違反します)(C99 以降)、動作は未定義です。dest または src が無効またはヌルポインタの場合の動作は未定義です。2) (1) と同じですが、実行時に以下のエラーが検出され、宛先範囲全体
[dest, dest + destsz) がゼロ埋めされ(dest と destsz の両方が有効な場合)、さらに現在インストールされている 制約ハンドラ 関数が呼び出される点が異なります:
destまたはsrcがヌルポインタであるdestszまたはcountが RSIZE_MAXcountより大きいdestszが- より大きい(バッファオーバーフローが発生する)
ソースと宛先のオブジェクトが重複している
dest < count < destsz が指す文字配列のサイズ = destsz である場合の動作は未定義です。言い換えれば、 の誤った値は差し迫ったバッファオーバーフローを露呈しません。
memcpy_s すべての境界チェック付き関数と同様に、__STDC_LIB_EXT1__ が実装によって定義され、かつユーザーが __STDC_WANT_LIB_EXT1__ を整数定数 1 に定義してから <string.h> をインクルードした場合にのみ利用が保証されます。引数
| dest | - | コピー先のオブジェクトへのポインタ |
| destsz | - | 宛先で変更する最大バイト数(通常は宛先オブジェクトのサイズ) |
| src | - | コピー元のオブジェクトへのポインタ |
| count | - | コピーするバイト数 |
戻り値
1)
dest のコピーを返します。2)
dest 成功時はゼロ、エラー時は非ゼロの値を返します。エラー時、destsz がヌルポインタでなく、destsz が有効な場合、宛先配列に ゼロバイトを書き込みます。
memcpyノート は、割り当て関数によって取得されたオブジェクトの有効な型を設定するために使用できます。
memcpy strcpy (コピーするデータをスキャンする必要がある)や memmove (重複入力を処理するための予防措置が必要)よりも通常は効率的で、メモリ間コピーのための最速のライブラリルーチンです。
いくつかのCコンパイラは、適切なメモリコピーループを memcpy 呼び出しに変換します。
strict aliasing が異なる型の値として同じメモリを調べることを禁止している場合、memcpy を使用して値を変換することができます。
例
このコードを実行する
#define __STDC_WANT_LIB_EXT1__ 1
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// simple usage
char source[] = "once upon a midnight dreary...", dest[4];
memcpy(dest, source, sizeof dest);
for (size_t n = 0; n < sizeof dest; ++n)
putchar(dest[n]);
// 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};
memcpy(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;
memcpy(&n, &d, sizeof d); // OK
printf("\n%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 = memcpy_s(dst,sizeof dst,src,5);
printf("dst = \"%s\", r = %d\n", dst,r);
r = memcpy_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
}
出力例:
once
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.1 memcpy 関数 (p: TBD)
- K.3.7.1.1 memcpy_s 関数 (p: TBD)
- C17 規格 (ISO/IEC 9899:2018):
- 7.24.2.1 memcpy 関数 (p: TBD)
- K.3.7.1.1 memcpy_s 関数 (p: TBD)
- C11 規格 (ISO/IEC 9899:2011):
- 7.24.2.1 memcpy 関数 (p: 362)
- K.3.7.1.1 memcpy_s 関数 (p: 614)
- C99 規格 (ISO/IEC 9899:1999):
- 7.21.2.1 memcpy 関数 (p: 325)
- C89/C90 規格 (ISO/IEC 9899:1990):
- 4.11.2.1 memcpy 関数
関連項目
(C23) |
指定された区切り文字の後で停止しながら、あるバッファを別のバッファにコピーする (関数) |
(C11) |
あるバッファを別のバッファに移動する (関数) |
(C95)(C11) |
重複しない2つの配列間である一定数のワイド文字をコピーする (関数) |
C++ ドキュメント の memcpy
| |