سؤال

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

struct Message
{
  unsigned int version : 3;
  unsigned int type : 1;
  unsigned int id : 5;
  unsigned int data : 6;
} __attribute__ ((__packed__));

على معالج Intel مع مترجم GCC، تم وضع الحقول في الذاكرة عند إظهارها. Message.version كان أول 3 بت في المخزن المؤقت، و Message.type يتبع. إذا وجدت خيارات تعبئة الهيكل المكافئ للمجمعات التحويلية المختلفة، فهل ستكون هذه منصة عرضية؟

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

المحلول

لا، لن تكون محمولة بالكامل. خيارات التعبئة للمويدات هي ملحقات، وهي نفسها غير محمولة بالكامل. بالإضافة إلى ذلك، تقول الفقرة 10 إلى ذلك، C99 §6.7.2.1: "ترتيب تخصيص حقول بت ضمن وحدة (ترتيب عالي الترتيب المنخفض أو الترتيب المنخفض إلى مرتبة عالية)."

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

نصائح أخرى

حقول بت تختلف على نطاق واسع من مترجم إلى مترجم، آسف.

مع دول مجلس التعاون الخليجي، تضع آلات نبيذ كبيرة من البتات الكبيرة الأولى والأختان النخلة القليل من الأجهزة التي تنتهي البتات قليلا.

تقول K & R "الأعضاء المجاورين [بت] من الهياكل معبأة في وحدات تخزين تعتمد على التنفيذ في اتجاه تعتمد على التنفيذ. عندما لا يناسب الحقل بعد حقل آخر ... قد يتم تقسيمه بين الوحدات أو قد تكون الوحدة مبطن. مجال غير محدد من العرض 0 يجبر هذا الحشوة ... "

لذلك، إذا كنت بحاجة إلى تخطيط ثنائي مستقل في الجهاز، يجب عليك القيام بذلك بنفسك.

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

يجب تجنب Bitfields - أنها ليست محمولة للغاية بين المحاميلات حتى لنفس النظام الأساسي. من C99 Standard 6.7.2.1/10 - "هيكل وتحسين النقابات" (هناك صياغة مماثلة في معيار C90):

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

لا يمكنك ضمان ما إذا كان حقل بت "تمتد" حدود INT) ولا يمكنك تحديد ما إذا كان Bitfield يبدأ في المنخفضة نهاية Int أو نهاية Int (هذا مستقل عما إذا كان المعالج Big-Endian أو Little-Endian).

تفضل bitmasks. استخدم "طيران" (أو حتى وحدات الماكرو) لتعيين البتات واختبارها واختبارها.

نتحدث عن طلبات البايتات ليس الطلبات قليلا. في الوقت الحاضر ، هو 99٪ متأكد من أن طلبيات البت ثابتة. ومع ذلك، عند استخدام Bitfields، يجب أن تؤخذ الانتخاب في الاعتماد. انظر المثال أدناه.

#include <stdio.h>

typedef struct tagT{

    int a:4;
    int b:4;
    int c:8;
    int d:16;
}T;


int main()
{
    char data[]={0x12,0x34,0x56,0x78};
    T *t = (T*)data;
    printf("a =0x%x\n" ,t->a);
    printf("b =0x%x\n" ,t->b);
    printf("c =0x%x\n" ,t->c);
    printf("d =0x%x\n" ,t->d);

    return 0;
}

//- big endian :  mips24k-linux-gcc (GCC) 4.2.3 - big endian
a =0x1
b =0x2
c =0x34
d =0x5678
 1   2   3   4   5   6   7   8
\_/ \_/ \_____/ \_____________/
 a   b     c           d

// - little endian : gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
a =0x2
b =0x1
c =0x34
d =0x7856
 7   8   5   6   3   4   1   2
\_____________/ \_____/ \_/ \_/
       d           c     b   a

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

إذا كنت حقا بحاجة إلى الحصول على معلومات ثنائية متطابقة، فستحتاج إلى إنشاء Bitfields مع Bitmasks - على سبيل المثال، يمكنك استخدام رسالة قصيرة غير موقعة (16 بت) للرسالة، ثم قم بعمل أشياء مثل VersionMask = 0xe000 لتمثيل البتات الثلاثة الأعلى.

هناك مشكلة مماثلة في محاذاة داخل الهياكل. على سبيل المثال، تعتبر SPARC و PowerPC و 680 × 0 وحدة المعالجة المركزية الإناثية الكبيرة، والتقعة المشتركة للمجمعات المبرحة SPARC و PowerPC هي محاذاة أعضاء الهيكل على حدود 4 بايت. ومع ذلك، فإن مترجم واحد استخدمته لمدة 680 ×0 محاذاة فقط على حدود 2 بايت - وليس هناك خيار لتغيير المحاذاة!

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

كانت هذه مشكلة في مشروع واحد عملت عليه، لأن عملية الخادم التي تعمل على SPARC ستقوم بالاستعلام عن عميل ومعرفة ذلك كان كبيرا من الإناث، ويفترض أنه يمكن أن تبحروا بالضغط على الهياكل الثنائية على الشبكة ويمكن للعميل التعامل معه. وهذا يعمل بشكل جيد على عملاء PowerPC، وتحطمت وقتا كبيرا على عملاء 680x0. لم أكتب التعليمات البرمجية، واستغرق الأمر بعض الوقت للعثور على المشكلة. ولكن كان من السهل إصلاح بمجرد فعلت.

بالطبع أفضل إجابة هي استخدام فئة تقرأ / تكتب حقول بت كتدفق. باستخدام البنية الميدانية C. غير مضمون فقط. ناهيك عن أنه يعتبر غير مهني / كسول / غبي لاستخدام هذا في الترميز العالمي الحقيقي.

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