首页 文章

将字节数组初始化为某个值,而不是默认的null? [重复]

提问于
浏览
132

这个问题在这里已有答案:

我正在忙于将用C语言完成的旧项目重写为C# .

我的任务是重写程序,使其尽可能接近原始程序 .

在一堆文件处理过程中,编写该程序的前一个开发人员创建了一个包含大量字段的结构,这些字段对应于必须写入文件的设置格式,因此所有这些工作都已经完成 .

这些字段都是字节数组 . 然后C代码使用 memset 将整个结构设置为所有空格字符( 0x20 ) . 一行代码 . 简单 .

这非常重要,因为此文件最终使用的实用程序是期望此格式的文件 . 我必须要做的是将此结构更改为C#中的类,但我找不到一种方法可以轻松地将每个字节数组初始化为所有空格字符 .

我最终要做的是在类构造函数中:

//Initialize all of the variables to spaces.
int index = 0;
foreach (byte b in UserCode)
{
    UserCode[index] = 0x20;
    index++;
}

这很好,但我确信必须有一个更简单的方法来做到这一点 . 当数组在构造函数中设置为 UserCode = new byte[6] 时,字节数组会自动初始化为默认的空值 . 我是否有办法让它在声明时变成所有空格,所以当我调用我的类'构造函数时,它会像这样直接初始化?还是一些 memset 般的功能?

13 回答

  • 4

    对于小型数组,使用数组初始化语法:

    var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
    

    对于较大的阵列,使用标准的 for 循环 . 这是最可读和最有效的方法:

    var sevenThousandItems = new byte[7000];
    for (int i = 0; i < sevenThousandItems.Length; i++)
    {
        sevenThousandItems[i] = 0x20;
    }
    

    当然,如果你需要做很多事情,那么你可以创建一个帮助方法来帮助保持你的代码简洁:

    byte[] sevenItems = CreateSpecialByteArray(7);
    byte[] sevenThousandItems = CreateSpecialByteArray(7000);
    
    // ...
    
    public static byte[] CreateSpecialByteArray(int length)
    {
        var arr = new byte[length];
        for (int i = 0; i < arr.Length; i++)
        {
            arr[i] = 0x20;
        }
        return arr;
    }
    
  • 2

    使用它来首先创建数组:

    byte[] array = Enumerable.Repeat((byte)0x20, <number of elements>).ToArray();
    

    <number of elements> 替换为所需的数组大小 .

  • 78

    你可以用Enumerable.Repeat()

    100个项目的数组初始化为0x20:

    byte[] arr1 = Enumerable.Repeat(0x20,100).ToArray();
    
  • 2
    var array = Encoding.ASCII.GetBytes(new string(' ', 100));
    
  • 2

    如果需要初始化一个小数组,可以使用:

    byte[] smallArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
    

    如果你有一个更大的数组,那么你可以使用:

    byte[] bitBiggerArray Enumerable.Repeat(0x20, 7000).ToArray();
    

    这很简单,也很容易让下一个男/女孩阅读 . 并且99.9%的时间足够快 . (通常是BestOption™)

    但是,如果你真的需要超高速,那么使用P / invoke调用优化的memset方法是适合你的:(这里包含了一个很好用的类)

    public static class Superfast
    {
        [DllImport("msvcrt.dll",
                  EntryPoint = "memset",
                  CallingConvention = CallingConvention.Cdecl,
                  SetLastError = false)]
        private static extern IntPtr MemSet(IntPtr dest, int c, int count);
    
        //If you need super speed, calling out to M$ memset optimized method using P/invoke
        public static byte[] InitByteArray(byte fillWith, int size)
        {
            byte[] arrayBytes = new byte[size];
            GCHandle gch = GCHandle.Alloc(arrayBytes, GCHandleType.Pinned);
            MemSet(gch.AddrOfPinnedObject(), fillWith, arrayBytes.Length);
            return arrayBytes;
        }
    }
    

    用法:

    byte[] oneofManyBigArrays =  Superfast.InitByteArray(0x20,700000);
    
  • 4

    我之前的伙伴们给了你答案 . 我只是想指出你滥用foreach循环 . 看,因为你必须增加索引标准“for loop”不仅更紧凑,而且更高效(“foreach”做了很多事情):

    for (int index = 0; index < UserCode.Length; ++index)
    {
        UserCode[index] = 0x20;
    }
    
  • 3

    最快的方法是使用api:

    bR = 0xFF;

    RtlFillMemory(pBuffer,nFileLen,bR);

    使用指向缓冲区的指针,写入的长度和编码的字节 . 我认为在托管代码中执行它的最快方法(慢得多)是创建一小块初始化字节,然后使用Buffer.Blockcopy将它们写入循环中的字节数组 . 我把它扔到一起但没有测试过,但是你明白了:

    long size = GetFileSize(FileName);
    // zero byte
    const int blocksize = 1024;
    // 1's array
    byte[] ntemp = new byte[blocksize];
    byte[] nbyte = new byte[size];
    // init 1's array
    for (int i = 0; i < blocksize; i++)
        ntemp[i] = 0xff;
    
    // get dimensions
    int blocks = (int)(size / blocksize);
    int remainder = (int)(size - (blocks * blocksize));
    int count = 0;
    
    // copy to the buffer
    do
    {
        Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, blocksize);
        count++;
    } while (count < blocks);
    
    // copy remaining bytes
    Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, remainder);
    
  • 28

    只是为了扩展我的答案,一个更简洁的方式多次这样做可能是:

    PopulateByteArray(UserCode, 0x20);
    

    哪个叫:

    public static void PopulateByteArray(byte[] byteArray, byte value)
    {
        for (int i = 0; i < byteArray.Length; i++)
        {
            byteArray[i] = value;
        }
    }
    

    这有一个很好的循环效率(提到gwiazdorrr的答案)以及如果它被大量使用的漂亮整洁的调用 . 与我个人认为的枚举相比,一瞥可读 . :)

  • 4

    您可以使用collection initializer

    UserCode = new byte[]{0x20,0x20,0x20,0x20,0x20,0x20};
    

    如果值不相同,这将比_820142更好 .

  • 30

    此函数比填充数组的for循环更快 .

    Array.Copy命令是一种非常快速的内存复制功能 . 此函数通过重复调用Array.Copy命令并将我们复制的内容加倍,直到数组已满为止 .

    我在我的博客上讨论了这个问题http://coding.grax.com/2013/06/fast-array-fill-function-revisited.html

    请注意,通过在方法声明中添加单词"this",即 public static void ArrayFill<T>(this T[] arrayToFill ... ,这很容易变成扩展方法

    public static void ArrayFill<T>(T[] arrayToFill, T fillValue)
    {
        // if called with a single value, wrap the value in an array and call the main function
        ArrayFill(arrayToFill, new T[] { fillValue });
    }
    
    public static void ArrayFill<T>(T[] arrayToFill, T[] fillValue)
    {
        if (fillValue.Length >= arrayToFill.Length)
        {
            throw new ArgumentException("fillValue array length must be smaller than length of arrayToFill");
        }
    
        // set the initial array value
        Array.Copy(fillValue, arrayToFill, fillValue.Length);
    
        int arrayToFillHalfLength = arrayToFill.Length / 2;
    
        for (int i = fillValue.Length; i < arrayToFill.Length; i *= 2)
        {
            int copyLength = i;
            if (i > arrayToFillHalfLength)
            {
                copyLength = arrayToFill.Length - i;
            }
    
            Array.Copy(arrayToFill, 0, arrayToFill, i, copyLength);
        }
    }
    
  • 155

    这是标记为答案的帖子的更快版本的代码 .

    我所执行的所有基准测试表明,只有包含类似数组填充的简单for循环,如果递减则通常是两倍,而不是递增 .

    此外,数组Length属性已作为参数传递,因此无需从数组属性中检索它 . 它也应该预先计算并分配给局部变量 . 涉及属性访问器的循环边界计算将在循环的每次迭代之前重新计算边界的值 .

    public static byte[] CreateSpecialByteArray(int length)
    {
        byte[] array = new byte[length];
    
        int len = length - 1;
    
        for (int i = len; i >= 0; i--)
        {
            array[i] = 0x20;
        }
    
        return array;
    }
    
  • 1

    您可以使用Parallel类(.NET 4和更高版本)加速初始化并简化代码:

    public static void PopulateByteArray(byte[] byteArray, byte value)
    {
        Parallel.For(0, byteArray.Length, i => byteArray[i] = value);
    }
    

    当然你可以创造数组同时:

    public static byte[] CreateSpecialByteArray(int length, byte value)
    {
        var byteArray = new byte[length];
        Parallel.For(0, length, i => byteArray[i] = value);
        return byteArray;
    }
    

相关问题