جافا: كيف أقوم بإنشاء طريقة لاستخراج أجزاء مقسمة من عدد صحيح من مجموعة بايت باستخدام قناع

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

  •  02-10-2019
  •  | 
  •  

سؤال

أثناء العمل على فك تشفير بعض معايير دفق الفيديو ، لاحظت الكثير من الحالات التي يتم فيها توفير أجزاء من قيمة عدد صحيح في أي شيء من 2-6 بايت ولكن مفصولة بقطع محجوزة ، على النحو التالي:

// Specification (16 bits)
// -----------------------
// Reserved         1  bit
// Value A [6-7]    2  bit
// Reserved         2  bit
// Value A [4-5]    2  bit
// Reserved         3  bit
// Value A [0-3]    4  bit
// Reserved         2  bit

على سبيل المثال ، القيمة 185 (10111001 أو 0xB9) سيتم تخزينها على النحو التالي في صفيف بايت:

01000110 00100100

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

int w = 0;
w |= (0x60 & data[0]) >>> 5;  // extract the first 2 bits shifted to the front
w <<= 2;                      // bump them up 2 bits for the next section
w |= (0x06 & data[0]) >>> 1;  // extract the next 2 bits shifted to the front
w <<= 4;                      // bump them up 4 bits for the last section
w |= (0x3C & data[0]) >>> 2;  // extract the last 4 bits shifted to the front

// w now will equal 10111001 (185)

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

public static void testMethod() {

    byte[] data = new byte[] {0x46, 0x24}; // 01000110 00100100 
    int mask = 0x663C;                     // 01100110 00111100
    int x = readIntFromMaskedBytes(data, mask);

}

public static int readIntFromMaskedBytes(byte[] data, int mask) {
    int result = 0;

    // use the mask to extract the marks bits from each
    // byte and shift them appropriately to form an int

    return result;
}

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

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

زيلا

ملاحظة - عذر أي أخطاء في بناء الجملة في الرمز الزائف أعلاه ، فهو مجرد تصميم ليكون بمثابة تفسير لحالة الاستخدام.

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

المحلول

في الواقع ، أميل إلى الاعتقاد بأن قناع الخط والتحول المضمّن (إذا تم تنفيذه أكثر نظافة قليلاً من الرمز الكاذب) هو أفضل من محاولة كتابة طريقة للأغراض العامة. بالنسبة لمطور ذو خبرة من رمز الضرب من المستوى المنخفض ، يجب ألا تكون رمز القراءة والتحول مشكلة. إن المشكلة في طريقة الغرض العام على طول الخطوط التي تقترحها هي أنها ستكون أقل كفاءة ... ومن الصعب على برنامج التحويل البرمجي JIT لتحسينه.

راجع للشغل ، هكذا سأكتب الرمز.

// extract and assemble xxxx from yyyy 
int w = ((0x003C & data[0]) >> 2) | 
        ((0x0600 & data[0]) >> 6) | 
        ((0x6000 & data[0]) >> 7);

تعديل

ما زلت أرغب في فهم كيف يمكن ترميز مثل هذا النهج العام ، كتمرين تعليمي.

شيء من هذا القبيل:

public static int readIntFromMaskedBytes(int data, int mask) {
    int result = 0;
    int shift = 0;
    while (mask != 0) {
        if (mask & 1) {
            result |= (data & 1) << shift++;
        }
        data >>>= 1;
        mask >>>= 1;
    }
}

كما ترون ، سيستغرق ذلك ما يصل إلى 32 تكرار حلقة لإعطائك الإجابة. على سبيل المثال ، أقول أن هذا النهج أبطأ حوالي 10 مرات من الإصدار الأصلي.

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