• 0
محمد علاء الدين

البرمجه على مستوى ال Bit بإستخدام Bit-Fields

سؤال

بسم الله الرحمن الرحيم

يوجد باللغتين C++/C معاملات عديده للتعامل مع المتغيرات على مستوى البت و هم


& = bitwise and
| = bitwise or
^ = bitwise xor
~ = bitwise not
>> = left shift
<< = right shift

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

هذا النوع من البيانات متاح للغتين C++/C و يستخدم بكثره من مبرمجى العتاد و يسمى بـ Bit-Fields.

الـ Bit-Fields تتيح لك صنع متغير و تقسيم البيتات به على مجموعات مثل ان تقول النوع char يحتوى على 8 بت لذا سأقوم بجعل اول 3 بت بالإسم a و الخمس بتات الباقيه بإسم b. الـ Bit-Fields لا يمكن تعريفها إلا داخل union او structure او class و تكون كالتالى:


structure test
{
char a:3, b:5;
};

النوع test مساحته 1 بايت موزعه بقيمة 3 بت للمتغير a و 5 بت للمتغير b و حيث ان مساحة a 3 بت فهذا يعنى ان اكبر قيمه يستطيع ان يتحملها هى الرقم 7 و بالنسبه لـ b فأكبر قيمة يستطيع تحملها هى الرقم 31.

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

الأن لنعود للمزايا التى ستفتقدها:

1 - لا يمكنك استخدام المعامل sizeof مع احد الـ Bit-Fields

2 - لا يمكنك تمرير متغير Bit-Field بالمرجع.

3 - حيث انك لا تستطيع تمرير Bit-Field بالمرجع فهذا يعنى بالتبعيه انك لا تستطيع اخذ عنوانه.ع المزطبع المزايا التي ستفقدها ليست هينه و خصوصا رقم 3 و لكن انظر للجانب الأخر ستكون لديك امكانيات اللغه فى مساحات انت تحددها.

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


0 - Not a programmer
1 - C programmer
2 - C++ programmer
4 - Assembly programmer

هذا المثال كما ترى يمكن ان يستهلك على اقصى حد بت لذا يمكن استخدام bit-field للقيام بهذه المهمه و ترك الخمسه الباقيه لأمر أخر، كود المثال سيكون كالتالى:


#include <stdio.h>

typedef unsigned char uint8;

union data
{
struct { uint8 type:3, unused:5; };
struct { uint8 c:1, cpp:1, low:1; };
};

void getUserType(uint8 n);

int main()
{
getUserType(4);
}

void getUserType(uint8 n)
{
data user;

user.type = n;

if(user.type == 0)
{
printf("not a programmer.\n");
return;
}

if(user.c) printf("C programmer.\n");

if(user.cpp) printf("C++ programmer.\n");

if(user.low) printf("Assembly programmer.\n");

return;
}

قد ينظر البعض و يقول ما هذا الكود:



typedef unsigned char uint8;

union data
{
struct { uint8 type:3, unused:5; };
struct { uint8 c:1, cpp:1, low:1; };
};

هل هذا كله فقط لأعرف bit-filed و بالطبع الإجابه هى لا و لكن هذا الكود لتطبيق المثال:

فى البدايه قمت بتعريف union وذلك حتى تكون مساحته هى مساحة اكبر عنصر فيه و فى حالتنا هذه مساحته هى 1 بايت و داخله قمت بتعريف unnamed structure و السبب فى ذلك حتى يكون المتغيرات التى داخله تكون متتاليه فى الذاكره و ليست فوق بعضها بعدها قمت بعمل struct اخر و هذه المره قمت بعمل 3 متغيرات به مساحه كل منهم 3 بت و حيث ان هذا struct اخر فعندما تدخل قيمه داخل المتغير type فكأنك ادخلت القيمه داخل المتغيرات c و cpp و low حينها كل ما احتاج فعله هو التحقق ما اذا كانت قيمة اى من هذه المتغيرات الثلاثه 1 او صفر فإن كانت واحد فقط تم استخدم هذا المتغير و ان كان صفر فهو فارغ، باقى الكود مفهوم على ما اعتقد.

قد يقول البعض ان هذا الإسلوب سيئ جدا و لكن انتظر إن اردت احد التطبيقات الحقيقيه للـ bit-field سأعطيك واحدا و إن لم تفهمه فهذا لأنك لا تعرف اسمبلى.

معالجات انتل و amd تحتوى على ما يسمى Flags يتم تغيير حالة هذه الـ Flags بناءا على اخر عملية قام بها المعالج، لذا عندما اردت صنع emulator للبروسسور احتجت ان اقوم بعمل نوع معين يماثل هذه الـ Flags و بالطبع احتاج لأن تكون عملية الوصول لهم للحصول على القيمه منهم و وضع قيمه بهم اسرع ما يمكن لذا لا يوجد بديل فى هذه الحاله عن الـ bit-field، النوع الذى قمت بعمله يشبه التالى:


// represent a flag registers
union FR
{
unsigned char all; // all flags
struct {
unsigned char
CF:1, // Carry Flag
PF:1, // Parity Flag
ZF:1, // Zero Flag
SF:1, // Sign Flag
DF:1, // Direction flag
OF:1, // Overflow Flag
RV:2; // reserved
};
} flags;

حقيقة الـ bit-fields لها تطبيقات عديده اكبر من ان يتم شرحها فى هذا الدرس الذى كان هدفه هو تذكيرك بوجودها حتى ان احتجتها تجدها.

و الله ولي التوفيق

3

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

0 إجابة على هذا السؤال .

لاتوجد إجابات على هذا السؤال حتى الآن .

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .