السلام عليكــم ورحمـة الله وبركاتــه ،،
هذا أول درس أقدمه في المنتدى و ان شاء الله لن يكون الأخير, الدرس عنوانه غريب فهو يتحدث عن الGenerics في لغة الC و كما نعلم جميعاً هو أنه لا يوجد Generics في الC بل هي في اللغات الأكثر تطوراً ففي ال++C تُسمى Templates و في ال#C و الJava تُسمى Generics. اذن كيف يمكن للC أن تقوم بهذا ؟؟
أولاً ما هو الهدف من الGenerics ؟؟
الهدف الاساسي هو كتابة كود واحد بحيث يمكنه أن يعمل على أكثر من data type بمعنى أنه على سبيل المثال لو كتبت كود للعملية الشهيرة Swap بهذا الأسلوب
void swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}فهذه العملية ستعمل فقط على الintegers أو الأعداد الصحيحة,و اذا أردت أن أقوم بعمل Swap للfloat أو الdouble أو ربما structs يجب علي أن أكتب نسخة مناسبة لكل نوع و لكن الكود في النهاية فكرته واحدة, فما اقوم به هو
- تعريف متفير مؤفت
- نقل البيانات من المتغير الأول الى المؤقت
- نقل البيانات من المتغير الثاني للأول
- نقل البيانات من المتغير المؤقت الى المتغير الثاني
وكما قلنا سابقاً اذا كنت أستخدم لغة من اللغات الأحدث كان يمكنني فوراً أن أعتبر أن المتغير من نوع T و أجعل مستخدم العملية يقدم هذا النوع أثناء استدعاء العملية, لكن في الC يجب أن نفكر بطريقة أخرى..
و لنسأل نفسنا سؤال, ما هو المتغير؟
المتغير هو مساحة في الذاكره لها عنوان و مساحة, على سبيل المثال المتغير A من نوع int (اي 4 بايت) و موجود في العنوان (xxxx) في الذاكرة,
اذاً لو أمكننا اعطاء العملية Swap هذه المعلومات (المساحة و العنوان) للمتغيرات, دون تحديد النوع يمكننا أن نتعامل مع المتغيرات بطريقة عامةً (على الأقل هذا كل ما يهم الC).
اذن كبداية يمكننا أن نقول أن العملية Swap يمكن اعادة كتابة الprototype الخاص بها بهذه الطريقة
void swapgeneric(void* x, void* y, int size)
كما نرى أنه تم استخدام المتغيرات من نوع void* و التي ترمز الى عنوان المتغير في الذاكرة, كما أن المتغيرين من نفس الحجم و لهذا تم استخدام متغير واحدة لتحديد الحجم و هو size
حتى الان الموضوع رائع, كتبنا الprototype كيف يمكننا الان ان نعيد كتابة الخطوات الأربع التي تم ذكرها سابقاً
بالنسبة للخطوة 1 و هي تعريف متغير مؤفت
- تعريف متغير مؤفت
كيف يمكن تعريف متغير دون استخدام نوع ؟؟؟
كما قلنا في السابق المتغير هو عنوان و مساحة و لهذا توجد ادالة malloc و التي تشبه في عملها الأمر new في ال++C و ال#C و هي دالة تقوم بحجز مساحة في الذاكرة يحددها المستخدم و تعيد مؤشر من نوع void* يُشير الى أول byte في هذه المساحة التي تم حجزها في الHeap
و هنا نكتب الكود هكذا
void* tmp = malloc(size);
if(tmp == NULL)
{
printf("no memory available\n");
return;
}ثم ننتقل الى الجزء الثاني من العملية و هو
2. نقل البيانات من المتغير الأول x الى المتغير المؤقت
كيف سننقل البيانات بطريقة عامة؟
البيانات في النهاية هي عبارة عن ترتيب معين للأصفار و الاحاد في الذاكرة, اذاً كل ما أحتاجه هو أن أنسخ هذا الترتيب دون الحاجة لمعرفة تفاصيل البيانات أو ما المقصود بها و نسخها من المساحة المُشار عليها بالمؤشر x الى المساحة المًشاؤ عليها بالمؤشر tmp, أي بطريقة أبسط نسخ عدد من البايتات يساوي size من المكان x الى المكان tmp و يتم هذا عن طريق الدالة memcpy و هي التي تقوم بنسخ البيانات من مكان في الذاكرة الى اخر
memcpy(tmp, x, size);
ثم نأتي للعملية الثالثة و هي مشابهة للعملية 2 و لكن سنقوم بنقل البيانات من المتغير y الى x
memcpy(x, y, size);
ثم العملية الرابعة و هي أيضاً مشابهة للعمليتين 2 أو 3
memcpy(y, tmp, size);
ثم سنحتاج كعملية أخيرة هو اعادة الذاكرة التي تم حجزها للمتغير tmp مرة اخرى للنظام, فلغة الC لا تقوم بهذه العملية تلقائياً بل من مهمة المطور أن يعيد الذاكرة الى النظام مرة اخرى بعد استخدامها و يكون هذا عن طريق الدالة free
free(tmp);
اذا اردنا الان أن نلقي نظرة على الكود كاملآ
void swapgeneric(void* x, void* y, int size)
{
void* tmp = malloc(size);
if(tmp == NULL)
{
printf("no memory available\n");
return;
}
memcpy(tmp, x, size);
memcpy(x, y, size);
memcpy(y, tmp, size);
free(tmp);
}و يمكننا استدعاء هذا الكود لأي نوع نحب على سبيل المثال
int x = 10;
int y=120;
printf("x=%d and y=%d\n", x, y);
swapgeneric(&x, &y, sizeof(int));
printf("x=%d and y=%d\n", x, y);أو على متغيرات نصية
char * t1 = "This is string 1";
char * t2 = "And this is string 2";
printf("t1=%s and t2=%s\n", t1, t2);
swapgeneric(&t1, &t2, sizeof(char *));
printf("t1=%s and t2=%s\n", t1, t2);أو على متغيرات من نوع struct بفرض أن لدينا struct Person يحتوي على متغير للاسم و اخر للسن
struct Person p1, p2;
p1.age = 10;
p1.name = "Person 1";
p2.age = 20;
p2.name = "Person 2";
printf("P1 age %d, name %s\n", p1.age, p1.name);
printf("P2 age %d, name %s\n", p2.age, p2.name);
swapgeneric(&p1, &p2, sizeof(struct Person));
printf("P1 age %d, name %s\n", p1.age, p1.name);
printf("P2 age %d, name %s\n", p2.age, p2.name);أرجو أن يكون الدرس سهل الاستيعاب و أرجو أن أرى تفاعلكم و أسئلتكم.
و شكراً


