تحويل Endianess على حقل بت هيكل
-
05-09-2019 - |
سؤال
أنا في حاجة لتحويل قليلا-ميدان هيكل من 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];
يجب ألا تستخدم حقول بت عندما يكون التصميم الفعلي مهم لأنه محدد بالتنفيذ حيث يتم ملء الطلب بكلمة أكبر.