none
Byte配列を、Uint32配列に変換したい RRS feed

  • 質問

  • リトルエンディアンで成り立っているByte配列 を、Uint32の配列として扱いたいと思います。

    Byte [] a = new byte[64];
    
    a[0] = 0x0f;
    a[1] = 0x00;
    a[2] = 0x00;
    a[3] = 0x00;
    a[4] = 0x0e;
    a[5] = 0x00;
    a[6] = 0x00;
    a[7] = 0x00;
    // 続く ↑
    
    //これを、UINT32の表現にしたい
    
    UInt32[] aa = new UInt32[16];
    
    aa[0] = 0x0f000000;
    aa[1] = 0x0e000000;
    // 続く ↑
    <br/>
    

    上記の様に、4バイト長のバイト配列をUint32配列として扱うには

    どの様にしたら良いですか。

    以上、よろしくお願いします。

    2011年6月15日 6:50

回答

  • taokatoさんこんばんは、おのでらです。

    力技ですがこんな感じでしょうか。(未検証です。型キャストあたりで警告がでるかビルドエラーになるかは不明)

    UInt32[] aa = new UInt32[16];
    
    for (int i = 0; i < 16; i++)
    {
     aa[i] = ((uint)a[i * 4] << 24) + ((uint)a[i * 4 + 1] << 16) + ((uint)a[i * 4 + 2] << 8) + (a[i * 4 + 3]);
    }
    
    


    おのでら (http://sorceryforce.com/)
    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 8:58
  • BitConverter.ToUInt32 メソッド を利用すれば良いと思います。

    BitConverter.ToUInt32 メソッド
    http://msdn.microsoft.com/ja-jp/library/system.bitconverter.touint32.aspx

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 8:58
    モデレータ
  • エンディアンが逆なような気がするけど

    class Program
    {
      static void Main(string[] args)
      {
    
        Byte[] a = new byte[8];
        Array.Clear(a, 0, a.Length);
        a[0] = 0x0f;
        a[1] = 0x00;
        a[2] = 0x00;
        a[3] = 0x00;
        a[4] = 0x0e;
        a[5] = 0x00;
        a[6] = 0x00;
        a[7] = 0x00;
    
        System.Diagnostics.Debug.WriteLine("**** 取り出すだけ *****");
        var q = from index in Enumerable.Range(0, a.Length / 4)
             select System.BitConverter.ToUInt32(a.Skip(index*4).Take(4).Reverse().ToArray(),0);
        UInt32[] values = q.ToArray();
    
        foreach (uint ui in q)
        {
          System.Diagnostics.Debug.WriteLine(ui.ToString("X8"));
        }
    
        System.Diagnostics.Debug.WriteLine("**** 配列じゃないけどインデックスで出し入れ*****");
    
        a.SetUInt32_BigEndian(0, 0x12345678u);
    
        for (int index = 0; index < a.Length / 4; index++)
        {
          System.Diagnostics.Debug.WriteLine(a.GetUint32_BigEndian(index).ToString("X8"));
        }
      }
    }
    
    static class EndianConverter
    {
      public static UInt32 GetUint32_BigEndian(this byte[] array, int index)
      {
        byte[] bs = array.Skip(index * 4).Take(4).Reverse().ToArray();
        return System.BitConverter.ToUInt32(bs, 0);
      }
      public static void SetUInt32_BigEndian(this byte[] array, int index, uint value)
      {
        byte[] bs = System.BitConverter.GetBytes(value).Reverse().ToArray();
        Array.Copy(bs, 0, array, index * 4, bs.Length);
      }
    }


    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 9:07
  • みなさん回答されていますが、質問の前提条件としてエンディアンが気になります。質問には「リトルエンディアン」と書かれていますが、例を見る限りビッグエンディアンです。またエンディアンを問題とする場合、実行環境のエンディアンについても触れておくべきです。(99%リトルエンディアンで実行するとは思いますが、それでも書くべきです。)

    .NET Frameworkには様々なクラスがあり今回の用途に使えるもの使えないものを挙げておきます。(他の方の紹介と被ります。)

    • Array.Copy()
      データ型が異なってもコピーしてくれます。ただしaa[0] = a[0]、aa[1] = a[1]となるので今回は意図しない結果になります。
    • BitConverter.ToUInt32()
      32bit=4byte分をUInt32に変換してくれます。必要項目数分ループすることになるでしょう。質問がはっきりしていませんが、バイトオーダーを入れ替える必要があるかもしれません。
    • IPAddress.NetworkToHostOrder()
      ネットワークバイトオーダーからネイティブのエンディアンに変換してくれます。質問がはっきりしていませんが、ネットワークバイトオーダー=ビックエンディアンなので使えるかもしれません。必要項目数分ループすることになるでしょう。UInt32バージョンはありません。
    • Marshal.Copy()
      バイト配列の先頭アドレスがあればInt32配列に読み込んでくれます。UInt32バージョンはありません。
    • Marshal.UnsafeAddrOfPinnedArrayElement()
      固定されてあれば配列の先頭アドレスを取得できます。
    • GCHandle.Alloc()
      GCHandleType.Pinnedを使用することでオブジェクトを固定できます。

    これだけ紹介してもエンディアンの変換が絡む場合、そのままずばりというものがありません。その場合のおすすめはおのでらさんが書かれているような、クラスライブラリを特に使わず希望する処理を行うループを書くことです。

    • 回答としてマーク taokato 2011年6月15日 23:36
    2011年6月15日 10:13

すべての返信

  • taokatoさんこんばんは、おのでらです。

    力技ですがこんな感じでしょうか。(未検証です。型キャストあたりで警告がでるかビルドエラーになるかは不明)

    UInt32[] aa = new UInt32[16];
    
    for (int i = 0; i < 16; i++)
    {
     aa[i] = ((uint)a[i * 4] << 24) + ((uint)a[i * 4 + 1] << 16) + ((uint)a[i * 4 + 2] << 8) + (a[i * 4 + 3]);
    }
    
    


    おのでら (http://sorceryforce.com/)
    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 8:58
  • BitConverter.ToUInt32 メソッド を利用すれば良いと思います。

    BitConverter.ToUInt32 メソッド
    http://msdn.microsoft.com/ja-jp/library/system.bitconverter.touint32.aspx

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 8:58
    モデレータ
  • エンディアンが逆なような気がするけど

    class Program
    {
      static void Main(string[] args)
      {
    
        Byte[] a = new byte[8];
        Array.Clear(a, 0, a.Length);
        a[0] = 0x0f;
        a[1] = 0x00;
        a[2] = 0x00;
        a[3] = 0x00;
        a[4] = 0x0e;
        a[5] = 0x00;
        a[6] = 0x00;
        a[7] = 0x00;
    
        System.Diagnostics.Debug.WriteLine("**** 取り出すだけ *****");
        var q = from index in Enumerable.Range(0, a.Length / 4)
             select System.BitConverter.ToUInt32(a.Skip(index*4).Take(4).Reverse().ToArray(),0);
        UInt32[] values = q.ToArray();
    
        foreach (uint ui in q)
        {
          System.Diagnostics.Debug.WriteLine(ui.ToString("X8"));
        }
    
        System.Diagnostics.Debug.WriteLine("**** 配列じゃないけどインデックスで出し入れ*****");
    
        a.SetUInt32_BigEndian(0, 0x12345678u);
    
        for (int index = 0; index < a.Length / 4; index++)
        {
          System.Diagnostics.Debug.WriteLine(a.GetUint32_BigEndian(index).ToString("X8"));
        }
      }
    }
    
    static class EndianConverter
    {
      public static UInt32 GetUint32_BigEndian(this byte[] array, int index)
      {
        byte[] bs = array.Skip(index * 4).Take(4).Reverse().ToArray();
        return System.BitConverter.ToUInt32(bs, 0);
      }
      public static void SetUInt32_BigEndian(this byte[] array, int index, uint value)
      {
        byte[] bs = System.BitConverter.GetBytes(value).Reverse().ToArray();
        Array.Copy(bs, 0, array, index * 4, bs.Length);
      }
    }


    • 回答としてマーク taokato 2011年6月15日 23:37
    2011年6月15日 9:07
  • みなさん回答されていますが、質問の前提条件としてエンディアンが気になります。質問には「リトルエンディアン」と書かれていますが、例を見る限りビッグエンディアンです。またエンディアンを問題とする場合、実行環境のエンディアンについても触れておくべきです。(99%リトルエンディアンで実行するとは思いますが、それでも書くべきです。)

    .NET Frameworkには様々なクラスがあり今回の用途に使えるもの使えないものを挙げておきます。(他の方の紹介と被ります。)

    • Array.Copy()
      データ型が異なってもコピーしてくれます。ただしaa[0] = a[0]、aa[1] = a[1]となるので今回は意図しない結果になります。
    • BitConverter.ToUInt32()
      32bit=4byte分をUInt32に変換してくれます。必要項目数分ループすることになるでしょう。質問がはっきりしていませんが、バイトオーダーを入れ替える必要があるかもしれません。
    • IPAddress.NetworkToHostOrder()
      ネットワークバイトオーダーからネイティブのエンディアンに変換してくれます。質問がはっきりしていませんが、ネットワークバイトオーダー=ビックエンディアンなので使えるかもしれません。必要項目数分ループすることになるでしょう。UInt32バージョンはありません。
    • Marshal.Copy()
      バイト配列の先頭アドレスがあればInt32配列に読み込んでくれます。UInt32バージョンはありません。
    • Marshal.UnsafeAddrOfPinnedArrayElement()
      固定されてあれば配列の先頭アドレスを取得できます。
    • GCHandle.Alloc()
      GCHandleType.Pinnedを使用することでオブジェクトを固定できます。

    これだけ紹介してもエンディアンの変換が絡む場合、そのままずばりというものがありません。その場合のおすすめはおのでらさんが書かれているような、クラスライブラリを特に使わず希望する処理を行うループを書くことです。

    • 回答としてマーク taokato 2011年6月15日 23:36
    2011年6月15日 10:13
  • ご回答を頂き有難うございます。

    >エンディアンを問題とする場合、実行環境のエンディアンについても触れておくべきです。

    背景となる事柄を書くべきでしたね。 以後、注意します。

     

    ご回答を頂いた内容は、非常に参考になりました。 m(_ _)m

    2011年6月15日 23:36