Namespaces
Variants

memmove, memmove_s

From cppreference.net
< c ‎ | string ‎ | byte
定義先ヘッダ <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関数

関連項目

バッファを別のバッファにコピーする
(関数)
2つの配列間(重複する可能性あり)で指定された量のワイド文字をコピーする
(関数)