"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > وظائف مضمنة في C وC++

وظائف مضمنة في C وC++

تم النشر بتاريخ 2024-11-08
تصفح:289

Inline Functions in C and C

مقدمة

أضاف C الكلمة الأساسية المضمنة التي يمكن أن تسبق تعريف الوظيفة، مثل:

inline int max_int( int a, int b ) {
    return a > b ? a : b;
}

لإعطاء المترجم "تلميحًا" إلى أن البرنامج بشكل عام قد يستفيد في الأداء من الوظيفة المضمنة .

الوظيفة التي تم تضمينها تم توسيع الكود الخاص بها في كل نقطة يتم استدعاؤها بدلاً من تنفيذ آلية استدعاء الوظيفة العادية لـ:

  • حفظ السجلات.
  • دفع قيم الوسيطة إلى المكدس.
  • تنفيذ تعليمات الاستدعاء.
  • الوظيفة التي تقوم في النهاية بتنفيذ تعليمات الإرجاع.
  • استعادة السجلات.

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

تمت إعادة الكلمة الرئيسية المضمنة إلى C99، ولكن مع متطلبات مختلفة قليلاً - المزيد لاحقًا.

الاختلافات عن وحدات الماكرو

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

ماكرو مكافئ بشكل ساذج للدالة max_int():

#define MAX_INT(A,B)  A > B ? A : B  /* bad implementation */

يعاني من المشاكل التالية:

  • الوسائط الموسعة، على سبيل المثال، MAX(n & 0xFF, 8)، يمكن أن تؤدي إلى أسبقية عامل التشغيل الخاطئة.
  • الحجج التي لها آثار جانبية، على سبيل المثال، MAX(n , 8)، يمكن أن يكون لها آثار جانبية متعددة.
  • لا يوجد فحص نوعي للوسائط عند التعريف.
  • الأخطاء غالبًا ما تكون مطولة ويصعب قراءتها.

بالإضافة إلى ذلك، ماكرو:

  • يمكن تعديل الوسيطة الخاصة به (وهذا غالبًا ما يكون ليس ما تريده).

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

فقط تلميح

كما ذكرنا، التحديد المضمّن هو فقط "تلميح" للمترجم بأن البرنامج بشكل عام قد يستفيد من الأداء من الوظيفة المضمنة. المترجم حر في تجاهل التلميح.

لماذا؟ لأن هناك حالات لا تكون فيها فكرة جيدة أو مستحيلة. تكون الدالة إما غير مضمنة أو غير مضمنة عادةً عندما يكون أي مما يلي صحيحًا:

  • الوظيفة "كبيرة جدًا".
  • يمكنك استدعاء الوظيفة عبر مؤشر إلى وظيفة.
  • الدالة متكررة.
  • الوظيفة لها حلقة.

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

إذا لم يتمكن المترجم من تضمين وظيفة ما أو اختار عدم تضمينها، فإنه لا يحذرك من أنه لم يفعل ذلك (افتراضيًا). بعض المترجمين، على سبيل المثال، gcc، لديهم خيار -Winline الذي سيحذرك ويعطيك سبب عدم تضمين الوظيفة.

يشبه التحديد المضمّن التعليمات البرمجية القديمة التي تحدد التسجيل - وكلاهما مجرد تلميحات.

متى (ومتى لا) إلى المضمنة

بالنسبة لمعظم الوظائف، فإن الجزء الأكبر من تكلفة تنفيذ الوظيفة يقع في نص الوظيفة، وليس في آلية استدعاء الوظيفة. ومن ثم، لكي تكون الدالة مرشحة جيدة للتضمين، يجب عمومًا أن تكون:

  • صغيرة بما يكفي بحيث تهيمن تكلفة آلية استدعاء الوظيفة.
  • يستخدم في الأماكن التي يكون فيها الأداء مهمًا بالفعل، على سبيل المثال، في الحلقات الضيقة.

عندما تكون في شك، قم بتعريف الرمز الخاص بك. الاستخدام المضمن هو ليس كلمة رئيسية سحرية "تجعلني أسرع". بالإضافة إلى ذلك، يمكن أن يؤدي الإفراط في استخدام المضمنة إلى تضخم التعليمات البرمجية مما يجعل أداء برنامجك أسوأ بشكل عام.

للمزيد راجع المرض المضمن.

الوظائف التي غالبًا ما تكون مرشحة جيدة للتضمين تشمل:

  • "العبارات الفردية" مثل "الرسائل" و"المثبتات".
  • مغلفات بسيطة حول الاستدعاءات إلى وظائف أخرى توفر قيمًا محددة للوسائط أو تقوم بعمليات الإرسال.

وظيفة مضمّنة مثالية تعمل على زيادة الأداء و تقلل من حجم الكود.

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

التحسينات المضمنة

إذا تم بالفعل تضمين دالة مضمنة بواسطة المترجم، فبالإضافة إلى حذف التعليمات البرمجية الخاصة بآلية استدعاء الوظيفة العادية، قد يكون المترجم أيضًا قادرًا على:

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

لكي يتمكن المترجم من تضمين دالة، يجب أن يكون قادرًا على "رؤية"

تعريفها (وليس فقط إعلانها) في كل ملف .c أو .cpp يتم استخدامه فيه تمامًا مثل الماكرو. ومن ثم، يجب أن تكون الدالة المضمنة محددة في ملف رأس. عادة، يجب أن تحتوي الوظيفة، مثل أي شيء آخر، على تعريف واحد فقط

من خلال الالتزام بقاعدة التعريف الواحدة (ODR). ومع ذلك، نظرًا لأن تعريف الدالة المضمنة "يُرى" في ملفات ‎.c أو ‎.cpp متعددة، يتم تعليق ODR لهذه الوظيفة.

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

لتضمين دالة في لغة C، كل ما عليك فعله هو بادئة تعريف الدالة بكلمة مضمنة - هذا كل شيء. سيقوم المترجم و/أو الرابط تلقائيًا بتجاهل كافة التعريفات باستثناء تعريف واحد من الملف القابل للتنفيذ النهائي لك.

ومع ذلك، لتضمين دالة في لغة C، يجب عليك بالإضافة إلى ذلك

أن تخبر المترجم صراحةً في ملف .o لوضع التعريف الوحيد في حالة كون المترجم إما غير قادر أو غير راغب في تضمين دالة عبر مضمنة خارجية.

على سبيل المثال، في ملف .c واحد فقط، يمكنك الإعلان عن وظيفة مثل:

//util.c المضمنة الخارجية int max_int( int, int );
هذا يخبر المترجم "بوضع التعريف الوحيد لـ max_int() في util.o."

// util.c
extern inline int max_int( int, int );

ثابت مضمن int max_int( int a, int b ) { العودة أ> ب؟ أ : ب؛ }


إذا قمت بذلك، فعندئذ:

static inline int max_int( int a, int b ) {
    return a > b ? a : b;
}
لا يتعين عليك

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

بدءًا من لغة C 11، يمكن بدلاً من ذلك تعريف الدوال المضمنة بأنها constexpr، ولكن هذه قصة لوقت آخر.

مراجع

أسلوب ترميز نواة لينكس، §15 المرض المضمن.

الأسطورة والواقع حول المضمنة في C99.

  • الدليل المرجعي المشروح لـ C
  • ، مارغريت أ. إليس وبيارن ستروستروب، أديسون ويسلي، 1990، ISBN 0-201-51459-1، §7.1.2
  • محددات الوظائف
  • ، ص. 99-105.
بيان الافراج تم نشر هذه المقالة على: https://dev.to/pauljlucas/inline-functions-in-c-and-c-2040 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3