C LANGUAGE TECHNOLOGY

【C言語】memcpy関数とmemmove関数の違いと自作関数

2021年11月16日

悩んでいる人

C言語でmemcpy関数とmemmove関数の違いを教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOS(Linuxカーネル)の授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
  • プログラミング歴15年以上,習得している言語: C/C++PythonSolidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開
  • 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
  • 最近は自然言語処理AIイーサリアムに関する有益な情報発信に従事.
    • (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
    • (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.

こういった私から学べます.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

memcpy関数とmemmove関数の違い

memcpy関数は,メモリ領域srcの先頭nバイトをメモリ領域destにコピーします.

コピー元の領域とコピー先の領域が重なってはいけません.

正常にコピーできない可能性があり,未定義の動作になります.

memcpy関数の返り値は,destへのポインタです.

memmove関数は,メモリ領域srcの先頭nバイトをメモリ領域destにコピーします.

memcpy関数とは異なり,memmove関数はコピー元とコピー先のメモリ領域が重なってもよいです.

最初にsrcのバイトがsrcともdestとも重ならない一時的な配列にコピーされてから,一時的な配列からdestにバイトのコピーが行われたかのように動作します.

※一時的な配列がなくてもmemmove関数は実装可能です.自作関数で紹介します.

その代わり,memmove関数はmemcpy関数より実行時間が長いというデメリットがあります.(実際には無視できるくらいです.)

memmove関数の返り値は,destへのポインタです.

メモリ領域ではなく文字列をコピーするstrcpy関数の使い方を知りたいあなたはこちらからどうぞ.

memcpy関数とmemmove関数の利用例

memcpy関数とmemmove関数の利用例は以下になります.

GCCでコンパイルした場合の実行結果は以下になります.

3~4行目のsとtの文字列は,コピーするメモリ領域が重なっていないので,同じ「0123456789」になっていることがわかります.

5~6行目のmemcpy関数と7~8行目のmemove関数の結果は,コピーするメモリ領域が重なっているので異なる結果になると思ったのですが,同じ結果(それぞれ「0120123489」と「0123423489」)になっていますね...

GCCではmemcpy関数とmemmove関数が同じ結果になりました.

Clangでコンパイルした場合の実行結果は以下になります.

3~4行目と7~8行目の実行結果はGCCでコンパイルした場合と同様です.

5行目は「0120123189」で6行目は「0123123189」と,7~8行目とそれぞれ異なる結果になりました.

つまり,GCCとClangで動作結果が異なりますので,コピーするメモリ領域が重なる場合はmemmove関数を利用しましょう!

参考までにVisual Studioでビルドした場合の実行結果は以下になります.GCCと同様です.

memcpy関数とmemmove関数の自作関数

memcpy関数とmemmove関数の自作関数は以下になります.

mymemcpy関数はsrcの先頭からdestにコピーするため,コピーするメモリ領域が重なった場合(かつdestのアドレスがsrcのアドレスより大きい場合)は正常にコピーできません.

これに対して,mymemmove関数では,29行目のif文でdestのアドレスとsrcのアドレスを比較します.

destのアドレスsrcのアドレス以下の場合,srcの先頭からdestにコピーし,そうでなければsrcの末尾からdestにコピーします.

なので,mymemmove関数はコピーするメモリ領域が重なった場合でも正常にコピーできます.

実行結果は以下になります.

3~4行目と7~8行目の実行結果は同様です.

5行目は「0120120189」,6行目は「0120120189」と7~8行目とClangの場合と異なる結果になりましたが,正常にコピーできなかったという点は同様です.

まとめ

C言語でmemcpy関数とmemmove関数の違いと自作関数を紹介しました.

コピーするメモリ領域が重なった場合,memcpy関数とmemmove関数は,GCCとVisual Studioでは同じ結果,Clangでは異なる結果になりました.

memcpy関数とmemmove関数の違いは下表になります.

※実行速度の違いは実際には無視できるくらいです.

項目memcpy関数memmove関数
メモリ領域が重なった場合正常にコピーできない可能性がある
(未定義の動作)
GCC/Visual Studioは正常に動作
Clangは未定義の動作
正常にコピーできる
実行速度速い遅い

memcpy関数と似ているmemccpy関数を知りたいあなたはこちらからどうぞ.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , , , , , ,