programing

바이트 배열을 기본 null이 아닌 특정 값으로 초기화하시겠습니까?

javajsp 2023. 5. 24. 21:42

바이트 배열을 기본 null이 아닌 특정 값으로 초기화하시겠습니까?

저는 C++로 했던 오래된 프로젝트를 C#로 다시 쓰느라 바쁩니다.

저의 업무는 프로그램을 가능한 한 원본과 가깝게 다시 작성하는 것입니다.

이 프로그램을 작성한 이전 개발자는 파일을 처리하는 동안 파일을 작성해야 하는 설정된 형식에 해당하는 수많은 필드를 포함하는 구조를 생성하므로 모든 작업이 이미 완료되었습니다.

이 필드는 모두 바이트 배열입니다. C은 C++ 일다같습다니음과은는하코가를 사용하는 입니다.memset문자로 (체구조를모공설문다니정합전로자백든(다▁to니▁set▁charact전▁this설ers▁to0x20코드 한 줄.만만하다.

이 파일이 최종적으로 사용되는 유틸리티는 이 형식의 파일을 예상하기 때문에 매우 중요합니다.제가 해야 할 일은 이 구조체를 C#의 클래스로 변경하는 것이었지만, 저는 이 바이트 배열을 모든 공백 문자로 쉽게 초기화할 방법을 찾을 수 없습니다.

클래스 생성자에서 수행해야 하는 작업은 다음과 같습니다.

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

이것은 잘 작동하지만, 저는 이것을 하는 더 간단한 방법이 있을 것이라고 확신합니다.이 배이다음설정경우된로으열로 설정되어 있습니다.UserCode = new byte[6]생성자에서 바이트 배열은 기본 null 값으로 자동으로 초기화됩니다.선언과 동시에 모든 공간이 되어 우리 반의 생성자에게 전화를 걸 때 이렇게 바로 초기화되도록 할 수 있는 방법은 없을까요? 약간의 는일부.memset-기능과 유사합니까?

소규모 어레이의 경우 어레이 초기화 구문을 사용합니다.

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;
}

이를 통해 처음에 배열을 작성합니다.

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

를 바꿉니다.<number of elements>원하는 배열 크기를 사용합니다.

Enumerable을 사용할 수 있습니다.반복()

Enumerable.Repeat하나의 반복되는 값을 포함하는 시퀀스를 생성합니다.

100항배로 항목 0x20:

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

소규모 어레이를 초기화해야 하는 경우 다음을 사용할 수 있습니다.

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

어레이가 더 큰 경우 다음을 사용할 수 있습니다.

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

이것은 간단하고, 다음 남자/여자가 읽기 쉽습니다.99.9%의 시간에 충분히 빠릅니다.(일반적으로 최상의 옵션™이 될 것입니다.)

하지만 정말로 초고속이 필요하다면, 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);
        gch.Free();
        return arrayBytes;
    }
}

용도:

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

이것들이 도움이 될 수 있을까요?

C#에서 memset에 해당하는 것은 무엇입니까?

http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

내 앞에 있는 사람들이 당신에게 답을 주었습니다.각 루프에 대한 당신의 오용을 지적하고 싶습니다.참고로, "루프에 대한" 인덱스 표준을 증가시켜야 하기 때문에 더 소형일 뿐만 아니라 더 효율적일 것입니다("각각의 경우 후드 아래에서 많은 작업을 수행합니다).

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

이것은 정답으로 표시된 게시물의 코드를 더 빠른 버전입니다.

제가 수행한 모든 벤치마크는 어레이 채우기와 같은 것만 포함하는 단순 루프증가하는 경우에 비해 감소하는 경우가 일반적으로 두 배 더 빠르다는 것을 보여줍니다.

또한 arrayLength 속성이 매개 변수로 이미 전달되었으므로 array 속성에서 검색할 필요가 없습니다.또한 미리 계산하여 로컬 변수에 할당해야 합니다.속성 접근자를 포함하는 루프 경계 계산은 루프의 각 반복 전에 경계 값을 다시 계산합니다.

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;
}

제 답변을 확장하기 위해 여러 번 이 작업을 수행하는 더 나은 방법은 다음과 같습니다.

PopulateByteArray(UserCode, 0x20);

다음을 호출합니다.

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

이것은 루프 효율이 좋고(gwiazdorr의 답변에 대한 언급), 자주 사용되는 경우 깔끔해 보이는 통화의 장점이 있습니다.그리고 제가 개인적으로 생각하는 열거형보다 한 눈에 읽을 수 있는 많은 것들이 있습니다.:)

가장 빠른 방법은 api를 사용하는 것입니다.

bR = 0xFF;

RtlFillMemory(pBuffer, nFileLen, bR);

버퍼에 대한 포인터, 쓸 길이 및 인코딩된 바이트를 사용합니다.관리 코드에서 이 작업을 수행하는 가장 빠른 방법은 초기화된 바이트의 작은 블록을 만든 다음 버퍼를 사용하는 것입니다.루프의 바이트 배열에 쓰기 위해 복사본을 차단합니다.저는 이것을 함께 던졌지만 테스트하지는 않았지만, 여러분은 다음과 같은 아이디어를 얻습니다.

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);

이 기능은 배열을 채우기 위한 for 루프보다 훨씬 빠릅니다.

배열.복사 명령은 매우 빠른 메모리 복사 기능입니다.이 기능은 배열을 반복적으로 호출하여 이 기능을 활용합니다.명령을 복사하고 어레이가 가득 찰 때까지 복사하는 크기를 두 배로 늘립니다.

저는 이에 대해 https://grax32.com/2013/06/fast-array-fill-function-revisited.html 의 블로그에서 논의합니다(링크 업데이트 2019년 12월 16일).이 확장 방법을 제공하는 Nuget 패키지도 참조하십시오.http://sites.grax32.com/ArrayExtensions/

메서드 선언에 "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);
    }
}

수집 이니셜라이저를 사용할 수 있습니다.

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

이는 값이 동일하지 않은 경우보다 더 잘 작동합니다.

병렬 클래스(.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;
}

언급URL : https://stackoverflow.com/questions/6150097/initialize-a-byte-array-to-a-certain-value-other-than-the-default-null