【C言語】
memmoveの基本的な使い方
~memcpyとの違いは配列をずらす時~

error: Overlapping read/write in memcpy() is undefined behavior

警告:転送領域が重なったのでrestrict修飾違反の未定義動作
[-Wrestrict]

■この記事の概要

C言語で配列をずらす際、
memcpyを使うとバグの原因になります。

この記事では、memmoveを使った安全な配列操作の方法を解説します。


■memmoveとは

memmoveとは
名前にmoveとありますが
メモリを移動ではなくてコピーします。

似たような関数にmemcpyがあります。
memcpyとmemmoveの違いは
memcpy:
➡メモリコピー領域が重なっていては駄目
memmove:
➡メモリコピー領域が重なっていてもOK

ここではメモリコピー領域が重なった
配列をずらす事例を紹介します。

■memcpyで配列をずらすと転送領域重複違反

#include <stdio.h>
#include <string.h>

int  main(void){
    char    buf[]="0123456789";
    printf("%s\n",buf);
    memcpy(&buf[1],&buf[0],9);//右へ1文字ずらす
    printf("%s\n",buf);
}
+ gcc f1.c -O2
+ ./a.out
0123456789
0012345677

memcpy( )の転送領域が重なっているので
restrict 修飾違反となり未定義動作となります。

gccの
最適化なしでは意図した結果を得られましたが最適化ありでは意図しない結果となりました。

注意:

・最適化(ーOオプション使用)しないとこの警告は出ません。
・実験ではgccとclangの結果は異なりました。
・最適化レベルを変えると結果も変わりました。
※未定義動作なので環境によって結果が変わるかもしれません。


■memmoveで配列をずらすと安全

#include <stdio.h>
#include <string.h>

int  main(void){
    char    buf[]="0123456789";
    printf("%s\n",buf);
    memmove(&buf[1],&buf[0],9);//右へ1文字ずらす
    printf("%s\n",buf);
}
+ gcc f2.c -O2
+ ./a.out
0123456789
0012345678

memcpy( )の代わりに
memmove( )を使用すると
意図した結果を得られました。


参考:

C-FAQ 11.25: memcpy()とmemmove()の違いは。

http://www.kouno.jp/home/c_faq/c11.html#25