سؤال

أنا في حاجة لتحويل قليلا-ميدان هيكل من little-endian الكبيرة-endia العمارة.ما هي أفضل طريقة للقيام بذلك, كما سيكون هناك مسائل في حدود البايت, إذا كنت ببساطة مبادلة عناصر البنية.

السابقين الهيكل:

struct {
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
}; 
هل كانت مفيدة؟

المحلول 8

للحصول على هذا، أخيرا حصلت على حل (بعض ما مشتق من محلول EPATEL أعلاه). هذا إذا قمت بالتحويل من X86 إلى Solaris SPARC.

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

struct orig
{    
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
};

struct temp
{    
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
}temp;


func (struct orig *toconvert)
{
    struct temp temp_val;
    //Swap the bytes
    swap32byte((u32*)toconvert);
    //Now read the structure in reverse order - bytes have been swapped
    (u32*)&temp_val = (u32 *)toconvert;
    //Write it back to orignal structure
    toconvert->b6=temp_val.b6;
    toconvert->b5=temp_val.b5;
    toconvert->b4=temp_val.b4;
    toconvert->b3=temp_val.b3;
    toconvert->b2=temp_val.b2;
    toconvert->b1=temp_val.b1;

}

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

نصائح أخرى

يمكنك استخدام عدد صحيح 32 بت، واستخراج المعلومات منه باستخدام ومشغلي bitshift. مع ذلك في المكان، يمكنك ببساطة استخدام Htonl (المضيف إلى الشبكة، طويلة). ترتيب البايت الشبكة هو الإناود الكبير.

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

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

union {
    unsigned char x;
    struct {
        unsigned char b1 : 1;
        unsigned char b2 : 7;
    };
} abc;
abc.x = 0;
abc.b1 = 1;
printf( "%02x\n", abc.x );

إلا إذا كنت يحدث لديها وثائق مفصلة ، الطريقة الوحيدة لمعرفة ما إذا كان ذلك سيتم طباعة 01 أو 80 هو أن تحاول ذلك.

في رمز تنقل المشروع من MIPS إلى Linux / x86، فعلنا ذلك.

struct {

#ifdef __ONE_ENDIANESS__
    unsigned int    b1:1;
    unsigned int    b2:8;
    unsigned int    b3:7;
    unsigned int    b4:8;
    unsigned int    b5:7;
    unsigned int    b6:1;
#define _STRUCT_FILLED
#endif /* __ONE_ENDIANESS__ */

#ifdef __OTHER_ENDIANESS__
    unsigned int    b6:1;
    unsigned int    b5:7;
    unsigned int    b4:8;
    unsigned int    b3:7;
    unsigned int    b2:8;
    unsigned int    b1:1;
#define _STRUCT_FILLED
#endif /* __OTHER_ENDIANESS__ */

};

#ifndef _STRUCT_FILLED
#  error Endianess uncertain for struct
#else
#  undef _STRUCT_FILLED
#endif /* _STRUCT_FILLED */

وحدات الماكرو __ONE_ENDIANESS__ و __OTHER_ENDIANESS__ كان من المناسب للمترجم الذي استخدمناه حتى تحتاج إلى النظر في أي من المناسب لك ...

لديك قسمان 16 بت هناك (الحقول الثلاثة الأولى والحقول الثلاثة الأخيرة هي 16 بت).

هذا فقط 65536 مداخل. لذلك لديك جدول بحث يحمل إصدار عكس بعض الحقول. لف الهيكل في اتحاد مع بنية أخرى له حقول 16 بت لجعل هذا أسهل؟

شيء من هذا القبيل (غير مختبر، أنا لست بالقرب من مترجم C):

union u {
    struct {
        unsigned int    b1:1;
        unsigned int    b2:8;
        unsigned int    b3:7;
        unsigned int    b4:8;
        unsigned int    b5:7;
        unsigned int    b6:1;
     } bits;
     struct {
        uint16 first;
        uint16 second;
     } words
} ;

unit16 lookup[65536];

/* swap architectures */

void swapbits ( union u *p)
{
   p->words.first = lookup[p->words.first];
   p->words.second = lookup[p->words.second];
}

غادر سكان طاولة البحث كممارتمر للقارئ :)

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

تريد القيام بذلك بين القناة (الملف أو الشبكة) والهيكل الخاص بك. ممارستي المفضلة هي عزل الملف I / O من الهياكل عن طريق كتابة التعليمات البرمجية التي تقوم ببناء المخازن المؤقتة للملف في تمثيل معروف، ومطابقة رمز القراءة الذي ينعكس هذا التحول.

مثالك المحدد صعب للغاية أن تخمن في لأنه يتم تعريف bitfields لتكون غير موقعة sizeof(unsigned int) غير محمول بشكل خاص.

على افتراض غنيمة ذلك sizeof(int)==4 ثم الحصول على مؤشر إلى الهيكل وربما يحصل لك البايت الفردية على الإجابة التي تريدها.

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

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

char* dest = (char*)&yourstruct;
unsigned int orig = yourstruct;
char* origbytes = (char*)&orig;
dest[0] = origbytes[3];
dest[1] = origbytes[2];
dest[2] = origbytes[1];
dest[3] = origbytes[0];

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

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