memcpy関数について
memcpy関数について
C言語標準ライブラリ関数であるmemcpy関数について素朴(?)な疑問が生じたのですが
例えばint型の配列 iData[20] という配列にあるデータを
別のint型配列 idata[20] にコピーさせる必要があるとします。
その場合、memcpy関数をつかって とした時と
for文を使って としたとき
結果は同じになると思われますが、どちらの処理が早いのでしょうか?
また、深い理由がなければこっちを使った方がいい。 といったモノはあるのでしょうか?
やはり知らない人がいるかもしれないmemcpy関数よりは、for文を使った方がいいのでしょうか?
例えばint型の配列 iData[20] という配列にあるデータを
別のint型配列 idata[20] にコピーさせる必要があるとします。
その場合、memcpy関数をつかって とした時と
for文を使って としたとき
結果は同じになると思われますが、どちらの処理が早いのでしょうか?
また、深い理由がなければこっちを使った方がいい。 といったモノはあるのでしょうか?
やはり知らない人がいるかもしれないmemcpy関数よりは、for文を使った方がいいのでしょうか?
♪僕たちは まだ森の中 抜け出そう 陽のあたる場所へ
Re: memcpy関数について
実験してみました。
私のところでは、for文の方が2~3倍ほど速かったです。
他の方のところではどうなるかはわかりません。
私のところでは、for文の方が2~3倍ほど速かったです。
他の方のところではどうなるかはわかりません。
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#define N (10000000)
int main(void)
{
static int iData[N], idata[N];
int i;
struct timeval ts, te;
gettimeofday(&ts, NULL);
memcpy(idata, iData, sizeof(int) * N);
gettimeofday(&te, NULL);
printf("実行時間:%.6f秒\n",
te.tv_sec - ts.tv_sec + (te.tv_usec - ts.tv_usec) / 1000000.);
gettimeofday(&ts, NULL);
for (i = 0; i < N; i++) {
idata[i] = iData[i];
}
gettimeofday(&te, NULL);
printf("実行時間:%.6f秒\n",
te.tv_sec - ts.tv_sec + (te.tv_usec - ts.tv_usec) / 1000000.);
return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: memcpy関数について
基本的にmemcpyは悪しき習慣として有名です。
なぜなら、ちょっとしたミスで簡単にメモリアクセス違反を引き起こしたり、
C++ではpod以外のクラスをmemcpyすると未定義の動作を引き起こす可能性もあります。
計測の結果、仮にその処理系がmemcpyが速くても、
それを理由にmemcpyを使うのはかなり危険な思考だと思います。
C++ではfor分などの他、std::copyを使う方法もあります。可読性も地味にあがるかと思います。
なぜなら、ちょっとしたミスで簡単にメモリアクセス違反を引き起こしたり、
C++ではpod以外のクラスをmemcpyすると未定義の動作を引き起こす可能性もあります。
計測の結果、仮にその処理系がmemcpyが速くても、
それを理由にmemcpyを使うのはかなり危険な思考だと思います。
C++ではfor分などの他、std::copyを使う方法もあります。可読性も地味にあがるかと思います。
Re: memcpy関数について
memcpyは内部形式をデータ型に依らず最も高速なバイト数ごとにまとめてコピーします。
Visual C++でint型では不利ですが、short型やchar型ならmemcpyのほうが速くなるはずです。
一般的にintよりサイズが小さいとか構造体にいろんな型が混じっているときはmemcpyが有利です。
#構造体一個コピーするならふつうに代入すればコンパイラが良きに計らってくれます。
ゲームプログラムでは、バイナリデータをバッファにコピーするときとか可変長のデータを扱うときに使いますね。
Visual C++でint型では不利ですが、short型やchar型ならmemcpyのほうが速くなるはずです。
一般的にintよりサイズが小さいとか構造体にいろんな型が混じっているときはmemcpyが有利です。
#構造体一個コピーするならふつうに代入すればコンパイラが良きに計らってくれます。
ゲームプログラムでは、バイナリデータをバッファにコピーするときとか可変長のデータを扱うときに使いますね。
Re: memcpy関数について
実質的に違いはありませんが、
memcpyは構造体のパディング領域もそのままコピーするのに対して、
forを使って代入した場合は有効な領域のみコピーされているようです。
ですから結果が全く同じというわけではありません。
http://ideone.com/2pVql
[訂正]
ideone上の出力が"memcmp"になってますが"memcpy" の間違いです..
memcpyは構造体のパディング領域もそのままコピーするのに対して、
forを使って代入した場合は有効な領域のみコピーされているようです。
ですから結果が全く同じというわけではありません。
http://ideone.com/2pVql
[訂正]
ideone上の出力が"memcmp"になってますが"memcpy" の間違いです..
Re: memcpy関数について
#include <stdio.h>
#include <string.h>
typedef struct {
int x;
short y;
} foo;
int main(void)
{
int i;
foo a[20], b[20], c[20];
memset(a, 1, sizeof(foo) * 20);
memset(b, 2, sizeof(foo) * 20);
memset(c, 3, sizeof(foo) * 20);
memcpy(b, a, sizeof(foo) * 20);
for(i=0; i<20; i++) c[i] = a[i];
printf("memcpy : %d\n", memcmp(b, a, sizeof(foo) * 20));
printf("for : %d\n", memcmp(c, a, sizeof(foo) * 20));
return 0;
}
Ubuntu11.04のgcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
Cygwinのgcc-4 (GCC) 4.3.4 20090804 (release) 1
VC++2010ExpressのMicrosoft(R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
ではmemcpy,forともに0と表示されました。
#パディングを比較して結果が違うというのがおかしな気がしますけど。
バイナリデータの圧縮伸張や画像・映像・音声処理等ではよく使われるのではないでしょうかね。
特にその手の組み込み分野でC++標準ライブラリのサポートをあてにはできませんし。
低レベル処理に手を出さず、既存ライブラリを使って賢くプログラミングすれば良いという考えにはある意味賛成です。
誰も低レベル処理に手を出さなくなったら困りますけどね。
Re: memcpy関数について
パディングごとmemsetでゼロクリアしているので、一致するのは当然ですね。ISLe さんが書きました:memcpy,forともに0と表示されました。
#パディングを比較して結果が違うというのがおかしな気がしますけど。
まあ、C言語の話をしているのにstd::copyを持ち出すのは論外としても、memcmpはそれなりに落とし穴もあります。
賢く使うのは賛成ですが、賢く使えるかどうかわからないプログラマは、いっそ手を出さない方が無難なのかもしれません。
Re: memcpy関数について
boxさんのコードだと、キャッシュの影響で、後半のほうが早くなる気がします。
私も実験してみたところ、memcpyの方がやや速いという結果になりました。
ideone.comでの結果 - http://ideone.com/yK8do
codepad.orgでの結果 - http://codepad.org/0hpCvEId
私も実験してみたところ、memcpyの方がやや速いという結果になりました。
ideone.comでの結果 - http://ideone.com/yK8do
codepad.orgでの結果 - http://codepad.org/0hpCvEId
#include <stdio.h>
#include <string.h>
#include <time.h>
#define N 10000000
int main(void)
{
// memcpy
{
static int src[N], dst[N];
clock_t start = clock();
memcpy(dst, src, N * sizeof(int));
printf("実行時間:%.6f秒\n", (clock() - start) / (double)CLOCKS_PER_SEC);
}
// for-loop
{
static int src[N], dst[N];
clock_t start = clock();
size_t i;
for (i = 0; i < N; ++i) {
dst[i] = src[i];
}
printf("実行時間:%.6f秒\n", (clock() - start) / (double)CLOCKS_PER_SEC);
}
return 0;
}
Re: memcpy関数について
C では、構造体の代入は、パディングも含めて構造体全体のビットパターンのコピーですから、代入も memcpy も結果は同じでしょう。
C++ で、operator= を定義したクラスをメンバとして含むクラスのインスタンスの代入は、メンバごとの代入になりますから、パディングはコピーされません。
C++ で、operator= を定義したクラスをメンバとして含むクラスのインスタンスの代入は、メンバごとの代入になりますから、パディングはコピーされません。
Re: memcpy関数について
すみません。どこでゼロクリアされているのか教えていただけませんか?たかぎ さんが書きました:パディングごとmemsetでゼロクリアしているので、一致するのは当然ですね。
パディングの中身をどうするかは決まってなかったと思うのですが、暗黙的にmemsetでゼロクリアする仕様ってありましたっけ。
memcpyを直接使わなくてもmemcpyを使う場合と同等かそれ以上に処理系が最適化してくれることを示したつもりなのですが、それを否定する投稿をされる意図は何ですか?たかぎ さんが書きました:まあ、C言語の話をしているのにstd::copyを持ち出すのは論外としても、memcmpはそれなりに落とし穴もあります。
賢く使うのは賛成ですが、賢く使えるかどうかわからないプログラマは、いっそ手を出さない方が無難なのかもしれません。
memcpyを使うことを否定しているようでいてmemcpyを使わせる方向へ誘導しているようですが。
memcpyを使わせたくないのか使わせたいのかどちらなのでしょう。
(追記)
memcpyを賢く使う、なんて文言もどこからでてきたんでしょう。
最後に編集したユーザー ISLe on 2011年7月15日(金) 19:19 [ 編集 1 回目 ]
Re: memcpy関数について
いつのまにか構造体やクラスをコピーするのにmemcpyは是か非かという話になってる。
Re: memcpy関数について
すみません。
勘違いやら、悪文やらでご迷惑おかけしました。
1, 2, 3でクリアしていますね?
std::copyとmemcmpを同じ分の中で書いたのがダメでした。
賢く使うかどうかはmemcmpの話です。
memcpyに関しては、それでディープコピーまでやってくれると勘違いするような素人でなければ、使って問題ないと思います。
もちろん、memmoveとの使い分けができることも必須条件です。
勘違いやら、悪文やらでご迷惑おかけしました。
勘違いでした。ISLe さんが書きました:すみません。どこでゼロクリアされているのか教えていただけませんか?たかぎ さんが書きました:パディングごとmemsetでゼロクリアしているので、一致するのは当然ですね。
パディングの中身をどうするかは決まってなかったと思うのですが、暗黙的にmemsetでゼロクリアする仕様ってありましたっけ。
1, 2, 3でクリアしていますね?
ここは悪文でした。ISLe さんが書きました:memcpyを直接使わなくてもmemcpyを使う場合と同等かそれ以上に処理系が最適化してくれることを示したつもりなのですが、それを否定する投稿をされる意図は何ですか?たかぎ さんが書きました:まあ、C言語の話をしているのにstd::copyを持ち出すのは論外としても、memcmpはそれなりに落とし穴もあります。
賢く使うのは賛成ですが、賢く使えるかどうかわからないプログラマは、いっそ手を出さない方が無難なのかもしれません。
std::copyとmemcmpを同じ分の中で書いたのがダメでした。
賢く使うかどうかはmemcmpの話です。
memcpyに関しては、それでディープコピーまでやってくれると勘違いするような素人でなければ、使って問題ないと思います。
もちろん、memmoveとの使い分けができることも必須条件です。
Re: memcpy関数について
承知致しました。たかぎ さんが書きました:すみません。
勘違いやら、悪文やらでご迷惑おかけしました。
構造体やクラスをコピーするのにmemcpyは是か非かという話であれば、わたしは非ですね。
絶対に使ってはいけないと思います。
わたしがmemcpyを使うのは、オリジナルから位置も長さも不定のデータをバッファにコピーする場合くらいです。
構造体としてまとめてコピーする場合も少なくないですが、絶対ポインタを含まないデータなのでディープコピーじゃなくて困ることはありませんし。
ゲームプログラムではそういう処理がけっこうな割り合いを占めます。
- tk-xleader
- 記事: 158
- 登録日時: 14年前
- 連絡を取る:
Re: memcpy関数について
処理速度でいえば環境によります。最適化によって、memcpy(for文)が高速なコードが生成されることも、はたまた全く同一のコードが生成されることもあります。jay さんが書きました:結果は同じになると思われますが、どちらの処理が早いのでしょうか?
また、深い理由がなければこっちを使った方がいい。 といったモノはあるのでしょうか?
やはり知らない人がいるかもしれないmemcpy関数よりは、for文を使った方がいいのでしょうか?
深い理由がないのならどっちを使ってもいいと思います。知らない人が読むということを考えるのなら、そこにコメントで「配列のコピーを行う」とでも残しておけばいいのではないかと思います。
Re: memcpy関数について
まずはスレ立てした後で色々と立て込んでしまい、思ったより返信が遅れてしまって申し訳ないです。
そして僕が最初に求めた答えとしては
ちなみにa5uaさんのコードで試してみたところ、僕の環境ではmemcpyの方がやや早かったです。
使うかどうかは(そんなに多用することはまずないでしょうけど)
たかぎさんがおっしゃる通り
tkmakwins15さんがおっしゃる通りちゃんとコメント書いておけば知らない人が見ても問題はないでしょうしね
そして僕が最初に求めた答えとしては
が正解ということでよろしいのでしょうか?tkmakwins15 さんが書きました:処理速度でいえば環境によります。最適化によって、memcpy(for文)が高速なコードが生成されることも、はたまた全く同一のコードが生成されることもあります。
ちなみにa5uaさんのコードで試してみたところ、僕の環境ではmemcpyの方がやや早かったです。
使うかどうかは(そんなに多用することはまずないでしょうけど)
たかぎさんがおっしゃる通り
これが正解な気がします(まぁ、ホントの正解なんてないんでしょうけど)たかぎ さんが書きました:memcpyに関しては、それでディープコピーまでやってくれると勘違いするような素人でなければ、使って問題ないと思います。
もちろん、memmoveとの使い分けができることも必須条件です。
tkmakwins15さんがおっしゃる通りちゃんとコメント書いておけば知らない人が見ても問題はないでしょうしね
♪僕たちは まだ森の中 抜け出そう 陽のあたる場所へ