Back to Top

プログラムの覚書

Category: C#

.NET C#

C# 構造体とバイト配列(byte[])の変換

C#にて構造体(struct)からバイト配列(byte[])に内容のコピーをしたい時があります。

構造体とバイト配列のメモリーコピー方法は幾つかあり、またコピー速度も異なります。そのコピー方法を説明します。

サンプル構造体

unsafe struct Person 
{
    public fixed byte name[10];
    public fixed byte Age[5];
}

上記の構造体をもとに以下説明をします。

 

バイト配列(byte[])を構造体(struct)に変換する

構造体のサイズだけbyte配列を確保します。

Person pos = new Person();
int size = Marshal.SizeOf(pos);

byte[] buffer = new byte[size];

//bufferにデータコピー

 

Marshalを使用して構造体にコピーする

IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer, 0, ptr, size);
pos = (Person)Marshal.PtrToStructure(ptr, typeof(Person));
Marshal.FreeHGlobal(ptr);

 

GCHandleを使用して構造体にコピーする

GCHandle gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
pos = (Person)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(Person));
gch.Free();

 

ポインタで直接構造体にコピーする

unsafe
{
    fixed (byte* pbytes = buffer)
    {
        pos = *(Person*)pbytes;
    }
}

 

構造体(struct)をバイト配列(byte[])に変換する

Marshalを使用してバイト配列にコピーする

int size = Marshal.SizeOf(pos);

byte[] bytes = new byte[size];

//アンマネージメモリからメモリを割り当て
IntPtr ptr = Marshal.AllocHGlobal(size);

//マネージオブジェクトからアンマネージメモリにデータをマーシャリング
Marshal.StructureToPtr(pos, ptr, false);

//アンマネージデータをマネージのbyte[]にコピーする
Marshal.Copy(ptr, bytes, 0, size);

Marshal.FreeHGlobal(ptr);

 

GCHandleを使用してバイト配列にコピーする

int size = Marshal.SizeOf(pos);

byte[] bytes = new byte[size];

GCHandle gchw = GCHandle.Alloc(bytes, GCHandleType.Pinned);
Marshal.StructureToPtr(pos, gchw.AddrOfPinnedObject(), false);
gchw.Free();

 

ポインタで直接バイト配列にコピーする

int size = Marshal.SizeOf(pos);

byte[] bytes = new byte[size];

unsafe
{
    fixed (byte* pbytes = bytes)
    {
        *(Person*)pbytes = pos;
    }
}

 

 

Posted in C# | Leave a reply

C# メインループ

C#で通常メインループなど書くことは、ほぼないと思います。

メインループが必要とされるのは、ゲーム作成など一部のアプリケーションだと思われます。とりあえずメインループの基本的な書き方を記載します。

メインループ プログラム

using System;
using System.Windows.Forms;

static class MyMain
{
    //< 60FPSで処理
    private const int waitTimes = (int)(1000.0 / 60.0);

    [STAThread]
    static void Main()
    {
        Form01 MainForm = new Form01();     //< フォーム生成
        MainForm.Show();                    //< フォームの表示

        int targetTimes = System.Environment.TickCount & int.MaxValue;
        targetTimes += waitTimes;

        while (MainForm.Created)
        {
            int tickCount = System.Environment.TickCount & int.MaxValue;
            if (targetTimes <= tickCount)
            {
                // メインの処理
                MainForm.RenderFps(targetTimes);

                targetTimes = (targetTimes + waitTimes) & int.MaxValue;
            }

            System.Threading.Thread.Sleep(1);       //< スリープ処理
            Application.DoEvents();                 //< Windowメッセージ処理
        }
    }
}

※Sleepは処理を停止させる処理ですが、CPUの負荷率等を下げるのに必要です。

サブプログラム

using System;
using System.Windows.Forms;
using System.Drawing;

public partial class Form01 : Form
{
    private Label label1;

    public Form01()
    {
        InitializeComponent();
    }

    public void RenderFps(int targetTimes)
    {
        label1.Text = targetTimes.ToString();
    }

    private void InitializeComponent()
    {
        this.label1 = new System.Windows.Forms.Label();
        this.SuspendLayout();
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(96, 137);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(92, 12);
        this.label1.TabIndex = 0;
        this.label1.Text = "";
        // 
        // Form01
        // 
        this.ClientSize = new System.Drawing.Size(395, 322);
        this.Controls.Add(this.label1);
        this.Name = "Form01";
        this.Text = "表示フォーム";
        this.ResumeLayout(false);
        this.PerformLayout();
    }
}

 

 

Posted in C# | Leave a reply