سؤال

لدي بروتوكول يتطلب حقلًا طولًا يصل إلى 32 بت ، ويجب إنشاءه في وقت التشغيل لوصف عدد البايتات الموجودة في حزمة معينة.

الكود أدناه هو نوع من القبيح ، لكنني أتساءل عما إذا كان يمكن إعادة بناء هذا ليكون أكثر كفاءة أو سهلة الفهم.المشكلة هي أن الكود لن يولد بايت فقط لوصف طول الحزمة ، لذلك أقل من 255 بايت = 1 بايت من الطول ، أقل من 65535 = 2 بايت من الطول وما إلى ذلك ...

{
    extern char byte_stream[];
    int bytes = offset_in_packet;
    int n = length_of_packet;
   /* Under 4 billion, so this can be represented in 32 bits. */
    int t;
   /* 32-bit number used for temporary storage. */

    /* These are the bytes we will break up n into. */
    unsigned char first, second, third, fourth;

    t = n & 0xFF000000;
    /* We have used AND to "mask out" the first byte of the number. */
    /* The only bits which can be on in t are the first 8 bits. */
    first = t >> 24;
    if (t)  {
        printf("byte 1: 0x%02x\n",first );
        byte_stream[bytes] = first; bytes++;
        write_zeros = 1;
    }
    /* Now we shift t so that it is between 0 and 255. This is the first, highest byte of n. */
    t = n & 0x00FF0000;
    second = t >> 16;
    if (t || write_zeros) {
        printf("byte 2: 0x%02x\n", second );
        byte_stream[bytes] = second; bytes++;
        write_zeros = 1;
    }

    t = n & 0x0000FF00;
    third = t >> 8;
    if ( t || write_zeros) {
        printf("byte 3: 0x%02x\n", third );
        byte_stream[bytes] = third; bytes++;
        write_zeros = 1;
    }

    t = n & 0x000000FF;
    fourth = t;
    if (t || write_zeros) {
        printf("byte 4: 0x%02x\n", fourth);
        byte_stream[bytes] = fourth; bytes++;
    }
}
هل كانت مفيدة؟

المحلول

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

  1. استخراج التعليمات البرمجية المشتركة إلى وظيفة
  2. ضع حسابات متشابهة معًا لجعل الأنماط أكثر وضوحًا
  3. تخلص من المتغير الوسيط print_zeroes وكن صريحًا بشأن الحالات التي تقوم فيها بإخراج البايتات حتى لو كانت صفرًا (على سبيل المثال.البايت السابق كان غير صفر)

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

إليك الكود:

/* append byte b to stream, increment index */
/* really needs to check length of stream before appending */
void output( int i, unsigned char b, char stream[], int *index )
{
    printf("byte %d: 0x%02x\n", i, b);
    stream[(*index)++] = b;
}


void answer( char bytestream[], unsigned int *bytes, unsigned int n)
{
    /* mask out four bytes from word n */
    first  = (n & 0xFF000000) >> 24;
    second = (n & 0x00FF0000) >> 16;
    third  = (n & 0x0000FF00) >>  8;
    fourth = (n & 0x000000FF) >>  0;

    /* conditionally output each byte starting with the */
    /* first non-zero byte */
    if (first) 
       output( 1, first, bytestream, bytes);

    if (first || second) 
       output( 2, second, bytestream, bytes);

    if (first || second || third) 
       output( 3, third, bytestream, bytes);

    if (first || second || third || fourth) 
       output( 4, fourth, bytestream, bytes);
 }

أكثر كفاءة قليلاً من أي وقت مضى، و ربما سيكون من الأسهل فهم هذا التعديل على عبارات if الأربعة الأخيرة:

    if (n>0x00FFFFFF) 
       output( 1, first, bytestream, bytes);

    if (n>0x0000FFFF) 
       output( 2, second, bytestream, bytes);

    if (n>0x000000FF)  
       output( 3, third, bytestream, bytes);

    if (1) 
       output( 4, fourth, bytestream, bytes);

ومع ذلك، أوافق على أن ضغط هذا المجال يجعل آلة الحالة المتلقية معقدة للغاية.ولكن إذا لم تتمكن من تغيير البروتوكول، فإن قراءة هذا الرمز أسهل بكثير.

نصائح أخرى

يجب عليك حقًا استخدام حقل ذو عرض ثابت لطولك.

  • عندما يتعين على البرنامج الموجود على الطرف المتلقي قراءة حقل طول الحزمة الخاصة بك، فكيف يعرف أين يتوقف الطول؟
  • إذا كان من الممكن أن يصل طول الحزمة إلى 4 جيجابايت، فهل يهم حقًا الحمل الزائد بمقدار 1-3 بايت؟
  • هل ترى مدى تعقيد التعليمات البرمجية الخاصة بك بالفعل؟

جرب هذه الحلقة:

{
    extern char byte_stream[];
    int bytes = offset_in_packet;
    int n = length_of_packet; /* Under 4 billion, so this can be represented in 32 bits. */
    int t; /* 32-bit number used for temporary storage. */
    int i;

    unsigned char curByte;

    for (i = 0; i < 4; i++) {
        t = n & (0xFF000000 >> (i * 16));

        curByte = t >> (24 - (i * 8));
        if (t || write_zeros)  {
            printf("byte %d: 0x%02x\n", i, curByte );
            byte_stream[bytes] = curByte;
                            bytes++;
            write_zeros = 1;
        }

    }

}

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

int i;  
int write_zeros = 0;  
for (i = 3; i >=0 ; --i) {  
    t = (n >> (8 * i)) & 0xff;  
    if (t || write_zeros) {  
        write_zeros = 1;  
        printf ("byte %d : 0x%02x\n", 4-i, t);  
        byte_stream[bytes++] = t;
    }  
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top