المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : تمرير عدد غير محدود من الوسائط إلى التابع...


أحمد معتوقي
26-12-2004, 09:06
بسم الله الرحمن الرحيم


السلام عليكم ورحمة الله وبركاته....


تتميز لغة الـ C عن غيرها من اللغات بكثير من المرونة التي لا تتيحها غيرها، ومن بينها أنك تستطيع أن تمرر إلى التابع عدد غير محدود من الوسائط....

ما الحاجة لها....


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



كيف تكون القصة....


عندما أستدع تابع معين، وأمرر الوسائط له، يقوم المترجم بوضع هذه المتحولات في المكدس (وبترتيب معكوس كما عرفنا)، ويقوم جسم البرنامج باستخلاص هذه المتحولات من المكدس، ويمكن صنع هذه العملية بشكل يدوي...





إلا أن الـ Syntax المتعلق بلغة الـ C يدعم هذه العملية، بالإضافة لذلك، فهناك بعض الـ macros ( الموجودة في stdarg.h أو varargs.h)التي تدعم استخلاص المتحولات من المكدس وبالترتيب الذي مـُررت به...

آلية التنفيذ...


حتى نقوم بهذه العملية نقوم أولا باستدعاء التابع على الشكل:







int mysum(int num,...);\\for format







إن الـ (...) تدل على أن التابع - حين الاستدعاء - يقبل أكثر من عدد الوسائط (Parameters) الثابتة لديه، وهنا في مثالنا يقبل التابع وسيط واحد فما فوق دون أن يعطي المترجم اي أخطاء أثناء الترجمة.





وغالبا يمرر في الوسيط الأخير من الوسائط الثابتة عدد الوسائط المتغيرة العدد، وهذا عائد للمبرمج نفسه، والأسلوب الذي يعتمده.

عند بناء جسم التابع.....


الآن سننتقل إلى بناء جسم هذا التابع...





* في البداية أستخدم النمط va_list حتى أنشئ متحول مصفوفة (مؤشر) تشير إلى مكان المتحولات الموجودة في المكدس....

مثلا....

va_list ap;\\for format


* ثم بعد ذلك أستخدم الـ macro الذي يدعى va_start وذلك حتى أستطيع أن تهيئة هذا المؤشر ووضعه عند رأس الـ Stack حتى يأخذ الوسائط.





يكون ذلك بتمرير المتحول من نوع va_list كوسيط أولي(ap في مثالنا)، ثم بعد ذلك المتحول الأخير من الوسائط التي مررت للتابع(num في مثالنا)...



va_start(ap, msg);\\for format









* والآن حتى أحصل على كل وسيط أقوم باستدعاء الـ macro (va_arg) الذي يمرر له المتحول من نوع va_list كوسيط أولي(ap في مثالنا)، ثم بعد ذلك نوع المتحول المتوقع أخذها من المكدس، ويقوم هذا الـ macro بإزاحة المؤشر إلى الوسيط الذي يليه..





مثلا...



arg = va_arg(ap,int);\\for format








* بعد الانتهاء من استخلاص الوسائط، نقوم بإستدعاء الـ macro الأخير، والذي هو va_end، على الشكل:



va_end(ap);\\for format


ويصبح لدينا المثال كاملا كما في الشكل:



http://www.alepposoft.com/info/attachment.php?attachmentid=856

استخدام هذا التابع...



يمكن استخدام هذا التابع عن طريق تمرير عدد الوسائط أولا ثم الوسائط...





مثلا...



int sum = mysum(5,1,2,3,4,5);\\for format



تعليق...


يستخدم هذا الأسلوب في بعض المكاتب القياسية، ولعلك تستغرب إذا قلت لك أن التابع printf المشهور يستخدم هذا الأسلوب، وهو مصرح على الشكل:







int printf( const char,... ); \\for format



تسلية...


قم بإنشاء التابع الخاص بك والشبيه بتابع printf وليكن اسمه myprintf...



تمت والحمد لله رب العالمين....


إعداد: أحمد معتوقي.





كلية الهندسة المعلوماتية- طالب.

جميع الحقوق محفوظة لـ Alepposoft

محمد سامر سروجي
26-12-2004, 14:36
السلام عليكم

مشكور على المقالة أبو حميد

سؤال

بالنسبة للتابع printf و حتى أعرف كم هو عدد المتحولات الموجود بعد أول متحول
فهل أقوم بعد الحرف % ضمن متحول الدخل الأول و عددها هو عدد المتحولات التالية ؟؟
و كيف أعرف نمطها فهو متغير و بالتالي علي استنتاجه من المحرف الذي يلي %
هل هذه التوقعات صحيحة أم .....:cmm2:

أحمد معتوقي
26-12-2004, 15:45
تماما أبو سمرة...

والتابع في هذه الحالة لا يتجاوز حجمة بضعة أسطر...

ولكن ما يحتاجه إضافة لذلك هو خوارزمية تحويل المتحولات من النمط الرقمي إلى سلسلة من المحارف...

أي أنني عندما أمرر %d فإن علي بعد تحصيل المتحول من المكدس أن أحوله إلى سلسلة من المحارف بالخوارزميات المعروفة لدينا...

هذا كل ما يحتاجه هذا التابع....

jamal_m21
08-02-2005, 15:35
السلا م عليكم ورحمة الله وبركاته.....
شكراً جزيلاً لك يا أخ على جهودك

السهم الناري
12-03-2005, 18:29
السلام عليكم

هلا اخوي احمد شرح ممتاز وموضوع اكثر من جميل بس ملاحظة الرابط للبرنامج لا يعمل ياليتتضع البرنامج هنا.
وبالنسبة لدالة printf اشوفها واذا مانفعت معي اسألك عنها ان شاء الله.

الى القاء.