لماذا أحصل على الإخراج التالي عند عكس البتات في البايت؟

StackOverflow https://stackoverflow.com/questions/627728

  •  06-07-2019
  •  | 
  •  

سؤال

افتراض:

إن تحويل بايت [] من Endian Little إلى Big Endian يعني قلب ترتيب البتات في كل بايت من البايت [].

على افتراض أن هذا صحيح، حاولت ما يلي لفهم هذا:

byte[] data = new byte[] { 1, 2, 3, 4, 5, 15, 24 };
byte[] inverted = ToBig(data);

var little = new BitArray(data);
var big = new BitArray(inverted);

int i = 1;

foreach (bool b in little)
{
    Console.Write(b ? "1" : "0");
    if (i == 8)
    {
        i = 0;
        Console.Write(" ");
    }
    i++;
}

Console.WriteLine();

i = 1;

foreach (bool b in big)
{
    Console.Write(b ? "1" : "0");
    if (i == 8)
    {
        i = 0;
        Console.Write(" ");
    }
    i++;
}

Console.WriteLine();

Console.WriteLine(BitConverter.ToString(data));
Console.WriteLine(BitConverter.ToString(ToBig(data)));

foreach (byte b in data)
{
    Console.Write("{0} ", b);
}

Console.WriteLine();

foreach (byte b in inverted)
{
    Console.Write("{0} ", b);
}

طريقة التحويل:

private static byte[] ToBig(byte[] data)
{
    byte[] inverted = new byte[data.Length];

    for (int i = 0; i < data.Length; i++)
    {
        var bits = new BitArray(new byte[] { data[i] });
        var invertedBits = new BitArray(bits.Count);

        int x = 0;

        for (int p = bits.Count - 1; p >= 0; p--)
        {
            invertedBits[x] = bits[p];
            x++;
        }

        invertedBits.CopyTo(inverted, i);
    }

    return inverted;
}

يختلف ناتج هذا التطبيق الصغير عما توقعته:

00000001 00000010 00000011 00000100 00000101 00001111 00011000

00000001 00000010 00000011 00000100 00000101 00001111 00011000 

80-40-C0-20-A0-F0-18

01-02-03-04-05-0F-18

1 2 3 4 5 15 24 

1 2 3 4 5 15 24 

لسبب ما تظل البيانات كما هي، ما لم تتم طباعتها باستخدام BitConverter.

ما الذي لا أفهمه؟

تحديث

ينتج الكود الجديد المخرجات التالية:

10000000 01000000 11000000 00100000 10100000 11110000 00011000 

00000001 00000010 00000011 00000100 00000101 00001111 00011000 

01-02-03-04-05-0F-18

80-40-C0-20-A0-F0-18

1 2 3 4 5 15 24 

128 64 192 32 160 240 24 

لكن كما قيل لي الآن ، فإن طريقتي غير صحيحة على أي حال لأنني يجب أن أعلب البايتات وليس البتات؟

لقد أخبرني مطور الأجهزة الذي أعمل معه أن أقوم بعكس البتات لأنه لا يستطيع قراءة البيانات.

السياق حيث أستخدم هذا

التطبيق الذي سيستخدم هذا لا يعمل حقًا مع الأرقام.

من المفترض أن أحفظ دفقًا من البتات لحفظها في مكانها

1 = أبيض و 0 = أسود.

أنها تمثل بكسل الصورة النقطية 256x64.

يمثل البايت 0 إلى BYTE 31 الصف الأول من البكسلات 32 إلى BYTE 63 الصف الثاني من وحدات البكسل.

لدي كود يقوم بإخراج هذه البتات ...لكن المطور يخبرني أنهم في ترتيب خاطئ ...يقول أن البايتات جيدة لكن البتات ليست كذلك.

لذلك بقيت في حيرة من أمري :p

هل كانت مفيدة؟

المحلول

قد تكون طريقتك صحيحة في هذه المرحلة.هناك معاني مختلفة لـ endianness، ويعتمد ذلك على الأجهزة.

عادة، يتم استخدامه للتحويل بين منصات الحوسبة.يستخدم معظم بائعي وحدات المعالجة المركزية (الآن) نفس ترتيب البت، لكن ترتيب البايت مختلف لمجموعات شرائح مختلفة.هذا يعني أنه إذا كنت تقوم بتمرير int ذو 2 بايت من نظام إلى آخر، فإنك تترك البتات وحدها، ولكن تقوم بتبديل البايتات 1 و 2، على سبيل المثال:

int somenumber -> byte[2]: somenumber[high],somenumber[low] ->  
byte[2]: somenumber[low],somenumber[high] -> int newNumber

ومع ذلك، هذا ليس صحيحا دائما.لا تزال بعض الأجهزة تستخدم ترتيب BIT المقلوب، لذا قد يكون ما لديك صحيحًا.ستحتاج إما إلى الوثوق بمطور الأجهزة لديك.أو النظر في الأمر أبعد من ذلك.

أوصي بقراءة هذا على ويكيبيديا - فهو دائمًا مصدر رائع للمعلومات:

http://en.wikipedia.org/wiki/Endianness


تحتوي طريقة ToBig الخاصة بك على خطأ.

في نهايةالمطاف:

 invertedBits.CopyTo(data, i);
}

return data;

تحتاج إلى تغيير ذلك إلى:

byte[] newData = new byte[data.Length];
invertedBits.CopyTo(newData, i);
}
return newData;

أنت تقوم بإعادة تعيين بيانات الإدخال الخاصة بك، بحيث تتلقى كلا المصفوفتين معكوستين.المشكلة هي أن المصفوفات هي أنواع مرجعية، لذا يمكنك تعديل البيانات الأصلية.

نصائح أخرى

لا.Endianness يشير إلى ترتيب بايت, ، وليس بت.تقوم الأنظمة الطرفية الكبيرة بتخزين البايت الأكثر أهمية أولاً، بينما تقوم الأنظمة ذات النهاية الصغيرة بتخزين البايت الأقل أهمية أولاً.تبقى البتات الموجودة داخل البايت بنفس الترتيب.

يبدو أن وظيفة ToBig() الخاصة بك تقوم بإرجاع البيانات الأصلية بدلاً من البيانات التي تم تبديل البتات فيها.

كما قال greyfade بالفعل، فإن endianness لا يتعلق بترتيب البتات.

السبب في أن التعليمات البرمجية الخاصة بك لا تفعل ما تتوقعه، هو أن طريقة ToBig تغير المصفوفة التي ترسلها إليها.وهذا يعني أنه بعد استدعاء الطريقة، يتم قلب المصفوفة، و data و inverted هما مجرد مرجعين يشيران إلى نفس المصفوفة.

وإليك نسخة مصححة من الطريقة.

private static byte[] ToBig(byte[] data) {
   byte[] result = new byte[data.length];
   for (int i = 0; i < data.Length; i++) {
      var bits = new BitArray(new byte[] { data[i] });
      var invertedBits = new BitArray(bits.Count);
      int x = 0;
      for (int p = bits.Count - 1; p >= 0; p--) {
         invertedBits[x] = bits[p];
         x++;
      }
      invertedBits.CopyTo(result, i);
   }
   return result;
}

يحرر:
إليك طريقة تغير endianness لمصفوفة بايت:

static byte[] ConvertEndianness(byte[] data, int wordSize) {
    if (data.Length % wordSize != 0) throw new ArgumentException("The data length does not divide into an even number of words.");
    byte[] result = new byte[data.Length];
    int offset = wordSize - 1;
    for (int i = 0; i < data.Length; i++) {
        result[i + offset] = data[i];
        offset -= 2;
        if (offset < -wordSize) {
            offset += wordSize * 2;
        }
    }
    return result;
}

مثال:

byte[] data = { 1,2,3,4,5,6 };
byte[] inverted = ConvertEndianness(data, 2);
Console.WriteLine(BitConverter.ToString(inverted));

انتاج:

02-01-04-03-06-05

المعلمة الثانية هي حجم الكلمة.نظرًا لأن endianness هو ترتيب البايتات في الكلمة، فيجب عليك تحديد حجم الكلمات.

تحرير 2:
فيما يلي طريقة أكثر فعالية لعكس البتات:

static byte[] ReverseBits(byte[] data) {
    byte[] result = new byte[data.Length];
    for (int i = 0; i < data.Length; i++) {
        int b = data[i];
        int r = 0;
        for (int j = 0; j < 8; j++) {
            r <<= 1;
            r |= b & 1;
            b >>= 1;
        }
        result[i] = (byte)r;
    }
    return result;
}

إحدى المشاكل الكبيرة التي أراها هي أن ToBig يغير محتويات ملف data[] المصفوفة التي تم تمريرها إليها.

أنت تتصل بـ ToBig على مصفوفة اسمها data, ، ثم إسناد النتيجة إلى inverted, ، ولكن بما أنك لم تقم بإنشاء مصفوفة جديدة داخل ToBig، فقد قمت بتعديل كلا المصفوفتين، ثم تنتقل إلى التعامل مع المصفوفات data و inverted مختلفة في حين أنها ليست كذلك في الواقع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top