릴리즈 버전을 기준으로 할 때 unsafe가 제일 빠르다.

 

디버그 버전

 

 BitConverter

 50 ms

 Marshal

 802 ms

 unsafe

 140 ms

 

 

릴리즈 버전

 

 BitConverter

 49 ms

 Marshal

 631 ms

 unsafe

 32 ms

 

 

테스트 코드

class Program
{
 const int COUNT = 1000000;
 static void Main(string[] args)
 {
  var basearray = Enumerable.Range(0, 1024).Select(x => (byte)x).ToArray();

  var sw = Stopwatch.StartNew();
  for (var i = 0; i < COUNT; i++)
  {
   var buffer = BitConverter.ToInt64(basearray, 2);
  }
  sw.Stop();

  Console.WriteLine($"BitConverter {sw.ElapsedMilliseconds}ms");

  sw = Stopwatch.StartNew();
  for (var i = 0; i < COUNT; i++)
  {
   var buffer = BtoS<Int64>(basearray, 2);
  }
  sw.Stop();

  Console.WriteLine($"Marshal {sw.ElapsedMilliseconds}ms");

  sw = Stopwatch.StartNew();
  for (var i = 0; i < COUNT; i++)
  {
   var buffer = ToInt64(basearray, 2);
  }
  sw.Stop();

  Console.WriteLine($"unsafe {sw.ElapsedMilliseconds}ms");

 

  Console.ReadKey();
 }

 private static T BtoS<T>(byte[] bytes, int startIndex) where T : struct
 {
  GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
  T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + startIndex,
   typeof(T));
  handle.Free();
  return stuff;
 }

 unsafe static void PutBytes(byte* dst, byte[] src, int start_index, int count)
 {
  for (int i = 0; i < count; i++)
   dst[i] = src[i + start_index];
 }

 unsafe static Int64 ToInt64(byte[] bytes, int startIndex)
 {
  Int64 ret;

  PutBytes((byte*)&ret, bytes, startIndex, 8);

  return ret;
 }

}

 

 

출처: http://qiita.com/yu_ka1984/items/fa403894af35a3f3925c

 

 

저작자 표시
신고
by 흥배 2016.01.20 09:00

C#으로 클라이언트나 서버를 만들 때 C++에 비해서 가장 아쉬운 것이 클래스(혹은 구조체) byte[](C++로 보면 char* 입니다)로 바로 변환하지 못 한다는 것입니다.

 

클래스를 바로 byte[]로 변환만 할 수 있으면(혹은 반대로) 네트웍으로 받은 데이터를 처리

하는 것이 간단해지는데 C#으로는 그것이 쉽지 않아서 좀 피곤하기도 합니다.

처음에는 어떻게든 변환 해보려고 했는데 막상 해보니 이것도 나름 피곤하고 성능 상으로 좋지도 않아서 지금은 이 방법은 사용하지 않습니다.

 

아래는 클래스를 byte[]로 변환하는 코드입니다.

이 방법은 데브피아에서 찾았습니다.

 

    // 패킷 헤더 클래스
    [StructLayout(LayoutKind.Sequential)]//[StructLayout(LayoutKind.Sequential, Pack=1)]
    public class HEADER
    {
        public ushort a1;
       public ushort a2;
        public ushort a3;
        public ushort a4;
    }
   
    //
로그인 요청 클래스
    // GetBuffer
을 부모 클래스에서 정의하고 여기서는 상속 받지 않은 이유는 그렇게 하면 클래스의
    //
데이타를 복사 할 때 부모클래스의 크기(4바이트) 만큼을 앞에 계산 해버린다
    [StructLayout(LayoutKind.Sequential)]
    public class LoginAuthorRet
    {
        public LoginAuthorRet()
       {
            Header = new HEADER();
            acID = new byte[21];
            acPasswd = new byte[31];
        }

// 클래스의 있는 데이타를 메모리에 담아서 리턴 한다.
        public void GetBuffer( byte[] outBuffer )
        {
            if( 0 == outBuffer.Length )
                outBuffer = new byte[ MAX_PACKET_DATA ];

            unsafe
           {
                fixed(byte* fixed_buffer = outBuffer)
               {
                    Marshal.StructureToPtr(this, (IntPtr)fixed_buffer, false);
                }
            }
        }

        public HEADER Header;    //
헤더

        [MarshalAs(UnmanagedType.ByValArray, SizeConst=21)] public byte[] acID;          //
아이디
       [MarshalAs(UnmanagedType.ByValArray, SizeConst=31)] public byte[] acPasswd;    //
패스워드
    }

 

사용 예

LoginAuthorRet LoginPacket = new LoginAuthorRet();링크
LoginPacket.Header.a2 = PK_LOGIN_AUTHOR_REQ;
LoginPacket.Header.a3 = (ushort)(Marshal.SizeOf(LoginPacket)-Marshal.SizeOf(LoginPacket.Header));
               
int iIDLen = strID.Length;
int iPWLen = strPass.Length;
Buffer.BlockCopy( Encoding.ASCII.GetBytes(strID), 0, LoginPacket.acID, 0, iIDLen );
Buffer.BlockCopy( Encoding.ASCII.GetBytes(strPass ), 0, LoginPacket.acPasswd, 0, iPWLen );

byte[] packet1 = new byte[ MAX_PACKET_DATA ];
LoginPacket.GetBuffer( packet1 );
SendPacket( packet1, Marshal.SizeOf(LoginPacket) );

 

2. byte[] to struct

출처: http://qiita.com/maenotti_99/items/519047bee9fd19e6cb10

구조체

[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct Hoge
{
    /// <summary>     6:コード</summary>
    [MarshalAs( UnmanagedType.ByValArray, SizeConst = 6 )]
    public byte[]   Code;
}

변환 함수
static public object ToStr( byte[] byteData, Type type )
{
    GCHandle gch = GCHandle.Alloc( byteData, GCHandleType.Pinned );
    object result = Marshal.PtrToStructure( gch.AddrOfPinnedObject(), type );
    gch.Free();
    return result;
}

사용 방법
Hoge dataL = (Hoge)ToStr( byData, typeof( Hoge ) );

 

3. struct to byte[]

출처: http://qiita.com/yu_ka1984/items/969728290b05e15f07a9

public static byte[] ToByteArray<T>(this T structure) where T : struct
{
    byte[] bb = new byte[Marshal.SizeOf(typeof(T))];
    GCHandle gch = GCHandle.Alloc(bb, GCHandleType.Pinned);
    Marshal.StructureToPtr(structure, gch.AddrOfPinnedObject(), false);
    gch.Free();
    return bb;
}


신고
by 흥배 2009.03.21 12:17
| 1 |