2006年07月25日

C#でmemcpy

  
C#で、C言語の memcpy のようなことはできないのかな、と調べていたが、残念ながらそのようなメソッドはないようだ。
まあ、当たり前か。

System.Buffer クラスには、BlockCopy というメソッドがあるが、これは、Array 限定なので、今回の僕の要求は満たさない。

  public static void BlockCopy (
Array src,
int srcOffset,
Array dst,
int dstOffset,
int count
)

しかたないので、
  unsafe private static void MemCopy(byte* dst, byte* src, int count) {
while ( count-- > 0 ) {
*dst++ = *src++;
}
}

のようなコードを C#で書いた。まさか、C#でこんなコードを書くとは思わなかった。
ポインタを使うコードを書くなんて、何年ぶりだろう。

もちろん、このコードは、unsafe でマーキングしておかなければコンパイルできない。
/unsafe コンパイラ オプションを指定する必要もある。

さらに、呼び出すときは、
 unsafe {
byte[] buffer = new byte[length];
fixed ( byte* dst = buffer, src = srcBuff ) {
MemCopy(dst, src, length);
}
}

のように、fixed キーワードで、再配置を防ぐ必要がある。
うーん、面倒だ。


この記事へのコメント
Array.CopyTo じゃ駄目なんですか?
fixed しなくちゃならんということは、src も dst もマネージドな byte 配列なんですよね?

Posted by 渋木宏明(ひどり) at 2006年07月25日 22:44
コメントありがとうございます。
Array.CopyToというメソッドも有ったんですね。
やりたいことは、確かに、マネージドなbyte配列の操作なので、Array.CopyTo や Buffer.BlockCopyでも可能は可能なのですが...
かなり特殊かつ低レベルな処理なので、昔の感覚で、ポインタ使ったほうが便利かな、なんて思ったのが、そもそもの間違いなのかも。
この処理には、配列と操作の基点となるインデックスと長さが必要なのですが、アドレスと長さだけ受け取ればいいじゃん、みたいな...
再度見直してみたいと思います。
もう一度見直す機会を作っていただきありがとうございました。
Posted by Gushwell at 2006年07月26日 19:30
unsafe しても、for で回しているコードから最終的に x86 の string 命令が生成されることは無く、単純ループなコードが生成されてしまう予感がします。
なので、unsafe 無しで for で回してた時の差はあまり出ないと予想します。
て、ベンチ録ってみたわけではないので全部想像ですが (^^;
Posted by 渋木宏明(ひどり) at 2006年07月29日 09:28
そこまでシビアな速度が要求されているわけでもないので、どんなコードが生成されるかまでは意識してはいないです。
ただ、どれくらい速度の差がでるかは、興味のあるところですね。

その後、実装を続けて行き、結局自作の MemCopy(byte* dst, byte* src, int count)を呼び出す場面って意外と少ないことが判明。
コピーしながら、別の処理もやらないといけない、その別の処理もいくつかのパターンがあります。
これら全部を unsafeなコードで書くというのは、なんだかな〜、なんて思い始めています。
すべて byte配列で操作することになるような予感。
Posted by Gushwell at 2006年07月29日 11:40
速度が要らないなら Array.CopyTo() で良いんじゃないでしょか (^^;
大昔に GNDJ で少し議論したことがありますが、単純なバイト列の操作に関しては、配列/ポインタでそれほど性能差が出ることはありませんでした。
性能差が無いなら、さらに言えばそれほど性能が必要でもないなら、メモリ破壊の危険のある unsafe を使う意味は薄いと思います。
標準的な構成の ASP.NET や ClickOnce で再利用することの出来ないコードになってしまいますし。
Posted by 渋木宏明(ひどり) at 2006年07月29日 13:45
まあ、メモリ破壊については、それほど心配はしていません。

>標準的な構成の ASP.NET や ClickOnce で再利用することの出来ないコードになってしまいますし

そうなんですか。ClickOnceにもそういった制限があるのですね。unsafeなコードを書くのがはじめてなので、知りませんでした...
時間の空いたときに、調べてみようと思います。
今回はこれに該当しませんが、やはり、すべてをバイト配列として操作するのが良さそうですね。
Posted by Gushwell at 2006年07月31日 09:59
 

この記事へのトラックバックURL