Converting an int[] to byte[] in C#

75,164

Solution 1

If you want a bitwise copy, i.e. get 4 bytes out of one int, then use Buffer.BlockCopy:

byte[] result = new byte[intArray.Length * sizeof(int)];
Buffer.BlockCopy(intArray, 0, result, 0, result.Length);

Don't use Array.Copy, because it will try to convert and not just copy. See the remarks on the MSDN page for more info.

Solution 2

Besides the accepted answer (which I am now using), an alternative one-liner for Linq lovers would be:

byte[] bytes = ints.SelectMany(BitConverter.GetBytes).ToArray(); 

I suppose, though, that it would be slower...

Solution 3

A little old thread, it's 2022 now…
I had a bunch of shorts laying around (sorry, no ints ;-) ) and thought it would be cool to have them as a byte array instead. After reading about all the different ways to approach this, I was very confused and just started benchmarking my favourite ones.
(The code should be easy to apply to any base type.)
It uses BenchmarkDotNet to do the actual testing and statistical analysis.

using System;
using System.Linq;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace ArrayCastingBenchmark;

public class Benchy {
    private const int number_of_shorts = 100000;
    private readonly short[] shorts;

    public Benchy() {
        Random r = new(43);
        shorts = new short[number_of_shorts];
        for (int i = 0; i < number_of_shorts; i++)
            shorts[i] = (short) r.Next(short.MaxValue);
    }

    [Benchmark]
    public ReadOnlySpan<byte> SPANSTYLE() {
        ReadOnlySpan<short> shortSpan = new ReadOnlySpan<short>(shorts);
        return MemoryMarshal.Cast<short, byte>(shortSpan);
    }

    [Benchmark]
    public byte[] BLOCKCOPY() {
        byte[] bytes = new byte[shorts.Length * sizeof(short)];
        Buffer.BlockCopy(shorts, 0, bytes, 0, bytes.Length);
        return bytes;
    }

    [Benchmark]
    public byte[] LINQY() {
        return shorts.Select(i => (byte) i).ToArray();
    }

    [Benchmark]
    public byte[] BITCONVERTER() {
        byte[] bytes = shorts.SelectMany(BitConverter.GetBytes).ToArray();
        return bytes;
    }

    //[Benchmark]
    //public void BINARYWRITER() {
    //    var fhandle = File.OpenHandle("_shorts_binarywriter.bin", FileMode.Create, FileAccess.Write);
    //    var binaryWriter = new BinaryWriter(new FileStream(fhandle, FileAccess.Write));
    //    foreach (var shorty in shorts)
    //        binaryWriter.Write(shorty);
    //    binaryWriter.Flush();
    //    binaryWriter.Close();
    //    fhandle.Close();
    //}
}

internal class Program {
    static void Main(string[] args) {
        var summary = BenchmarkRunner.Run<Benchy>();
    }
}

I left the last one in, because if you just add a File.WriteAllBytes to the end of all methods and make them actually produce some output, suddenly BLOCKCOPY get's ever so slightly faster than SPANSTYLE on my machine. If anyone else experiences this or has an idea how this can happen, please tell me.

EDIT: Sorry, forgot to include the actual results (mind you: on my machine) as it runs for quite a while with the standard settings and all the warm-up.

 |       Method |              Mean |           Error |          StdDev |
 |------------- |------------------:|----------------:|----------------:|
 |    SPANSTYLE |         0.4592 ns |       0.0333 ns |       0.0666 ns |
 |    BLOCKCOPY |    15,384.8031 ns |     304.6014 ns |     775.3079 ns |
 |        LINQY |   175,187.7816 ns |   1,119.2713 ns |   1,046.9671 ns |
 | BITCONVERTER | 9,053,750.0355 ns | 330,414.7870 ns | 910,058.2814 ns |
Share:
75,164

Related videos on Youtube

soandos
Author by

soandos

Student. Third to earn the marshal badge on SuperUser profile for soandos on Stack Exchange, a network of free, community-driven Q&amp;A sites http://stackexchange.com/users/flair/375094.png profile for soandos on Project Euler, which exists to encourage, challenge, and develop the skills and enjoyment of anyone with an interest in the fascinating world of mathematics. http://projecteuler.net/profile/soandos.png

Updated on April 16, 2022

Comments

  • soandos
    soandos about 2 years

    I know how to do this the long way: by creating a byte array of the necessary size and using a for-loop to cast every element from the int array.

    I was wondering if there was a faster way, as it seems that the method above would break if the int was bigger than an sbyte.

    • Henk Holterman
      Henk Holterman about 13 years
      byte array and "bigger than short" mismatch.
    • soandos
      soandos about 13 years
      I meant that int is not one to one with a byte in terms of size.
    • Henk Holterman
      Henk Holterman about 13 years
      And short/ushort are not one to one with byte.
    • Henk Holterman
      Henk Holterman about 13 years
      @scandos: and do you want to convert 4 bytes to 1 int, ... etc. Please note the Edit link under your question.
    • soandos
      soandos about 13 years
      @henk: Apologies. I Did not think about it, but assumed that I could just load 4 bytes, then read them as an int. seems that it requires more "formatting" as not every 4 bytes was perhaps meant to be an int (smaller numbers require less space, and as stated above, directly casting leads to data loss).
  • soandos
    soandos about 13 years
    how does it know to get 4 bytes per int?
  • Daniel Hilgarth
    Daniel Hilgarth about 13 years
    It just copies the memory. It doesn't know about int or byte. The memory representation of result will be exactly the same as that of intArray.
  • Moop
    Moop over 10 years
    How would you do the reverse? Take a byte[] and copy it to a int[]?
  • Daniel Hilgarth
    Daniel Hilgarth over 10 years
    @Moop int[] result = new int[byteArray.Length / sizeof(int)]; Buffer.BlockCopy(byteArray, 0, result, 0, result.Length);
  • Zenima
    Zenima over 9 years
    You can also use the following, if you don't know the element type of a value type array compile time: byte[] result = new byte[Buffer.ByteLength((Array)valueTypeArray)];
  • Meirion Hughes
    Meirion Hughes over 8 years
    yeah, but its fine for a quick short unit test. proposed an edit as you don't need the v=> ... yptes(v)
  • Philippe Paré
    Philippe Paré almost 8 years
    Even works with multidimensional arrays! I'm impressed, thanks a lot.
  • Jonathan Vukadinovic
    Jonathan Vukadinovic over 6 years
    Just a correction for the inverse solution that Daniel provided (from byte[] to int[]) it should be: Buffer.BlockCopy(byteArray, 0, result, 0, byteArray.Length); => basically the last parameter should not be result.Length and instead byteArray,Length
  • Kiquenet
    Kiquenet about 5 years
    and convert UInt16[] ?
  • Kiquenet
    Kiquenet about 5 years
    Powershell: ([System.Text.Encoding]::ASCII.GetString($Monitor.SerialNumb‌​erID)).Replace("$([c‌​har]0x0000)","")
  • Dirk Boer
    Dirk Boer over 3 years
    do you need to take endianness into account i.e. if you are not sure if you would run on Linux or Windows?
  • Daniel Hilgarth
    Daniel Hilgarth over 3 years
    @DirkBoer: It depends on your scenario. Depending on the endianess, the bytes in an int are ordered differently, so the result will differ based on the endianess. If you need to ensure that the resulting byte array can be read correctly on any system, you should either normalize it to a known endianess first or communicate the endianess that was used on the system where the byte array was written. If you just want to read it again on the same system, you don't have to care.
  • Dirk Boer
    Dirk Boer over 3 years
    Hi @DanielHilgarth, thanks for your answer! Ok as I'm right now too lazy to build something I guess this will fly into my face some day when I switch my server to a different OS :) Thanks for taking your time to answer!
  • Daniel Hilgarth
    Daniel Hilgarth about 2 years
    The explanation for the speed of Span is that it doesn't actually create a copy of the data. A Span is just a glorified pointer. So, all your code is doing, is to create a new pointer to the same data. Also, your LINQ test is incorrect. Just casting a short to a byte will lose information because a short holds 16 bit of data and a byte only 8