حواجز التضمين
جزء من قسم Object Oriented Programming في رحلة C على Coddy — الدرس 2 من 61.
عندما يتم تضمين ملف رأس (header file) عدة مرات في مشروع ما، يرى المترجم (compiler) نفس التصريحات بشكل متكرر، مما يتسبب في حدوث أخطاء. يحدث هذا عادةً عندما تقوم ملفات متعددة بتضمين نفس ملف الرأس، أو عندما تقوم ملفات الرأس بتضمين بعضها البعض. تحل حواجز التضمين (Include guards) هذه المشكلة.
يستخدم حارس التضمين (include guard) ثلاثة من توجيهات المعالج المسبق لضمان معالجة محتويات الملف الرأسي (header) مرة واحدة فقط:
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
#endif
إليك كيفية عمل ذلك: يتحقق #ifndef MATH_UTILS_H مما إذا كان الرمز MATH_UTILS_H لم يتم تعريفه بعد. إذا لم يكن قد تم تعريفه، يستمر المعالج المسبق (preprocessor) ويقوم بتعريفه فوراً باستخدام #define MATH_UTILS_H. يتم تضمين كل شيء بين هذه النقطة و #endif في عملية التجميع (compilation).
في المرة الثانية التي يتم فيها تضمين هذا الملف الرأسي، يكون MATH_UTILS_H معرّفاً بالفعل، لذا يتم تخطي الكتلة بالكامل. عادةً ما يكون اسم الحارس هو اسم الملف بالأحرف الكبيرة مع استبدال النقاط والرموز الخاصة بشرطات سفلية.
كل ملف رأس (header file) تقوم بإنشائه يجب أن يحتوي على حواجز تضمين (include guards). هذه ممارسة قياسية تمنع أخطاء التجميع (compilation errors) وتجعل الكود الخاص بك آمناً للتضمين من أي مكان في مشروعك.
التحدي
سهللنقم بحماية ملف ترويسة (header file) من التضمين المزدوج عن طريق إضافة حراس التضمين (include guards). ستبني على أداة التحية من الدرس السابق، ولكن هذه المرة تأكد من أن الترويسة آمنة للتضمين عدة مرات.
ستقوم بإنشاء ملفين:
greet.h: ملف الترويسة الخاص بك الذي يحتوي على إعلان الدالة لـgreet. هذه المرة، قم بتغليف المحتويات بالكامل بحراس التضمين باستخدام الرمزGREET_H.main.c: ملفك الرئيسي الذي يتضمن الترويسة، وينفذ الدالةgreetويستدعيها منmain().
يجب أن تقبل الدالة greet معاملًا من نوع const char* للاسم وتطبع:
Hello, Alice!يجب أن يتبع ملف الترويسة الخاص بك هذا الهيكل:
#ifndef GREET_H
#define GREET_H
// إعلان الدالة هنا
#endifستتلقى مدخلاً واحداً: اسم (سلسلة نصية).
اطبع رسالة التحية تماماً كما هو موضح في التنسيق أعلاه، مع استبدال Alice بالاسم المقدم.
ورقة مرجعية
تمنع حواجز التضمين (Include guards) معالجة ملفات الرأس عدة مرات أثناء عملية التجميع، مما قد يتسبب في حدوث أخطاء.
يستخدم حاجز التضمين ثلاثة توجيهات للمعالج المسبق:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// محتويات ملف الرأس هنا
#endif
يتحقق #ifndef مما إذا كان الرمز لم يتم تعريفه. إذا لم يكن معرفاً، يقوم #define بتعريفه وتتم معالجة المحتويات. في عمليات التضمين اللاحقة، يكون الرمز معرفاً بالفعل، لذا يتم تخطي الكتلة بالكامل.
عادةً ما يكون اسم الحاجز هو اسم الملف بالأحرف الكبيرة مع استبدال النقاط والرموز الخاصة بشرطات سفلية.
يجب أن يحتوي كل ملف رأس على حواجز تضمين كممارسة قياسية.
جرّب بنفسك
#include <stdio.h>
#include "greet.h"
// TODO: قم بتنفيذ دالة greet التي تطبع "!Hello, <name>"
int main() {
char name[100];
scanf("%s", name);
// TODO: قم باستدعاء دالة greet مع الاسم
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات البرمجة التركيبية
ملفات الترويسةحواجز التضمينملفات المصدرالدوال الساكنةمراجعة: آلة حاسبة تركيبية4التغليف (Encapsulation)
مفهوم الـ Opaque Pointersتعريف الـ Opaque Structsالـ Getters والـ Settersالتحقق من البيانات في الـ Settersملخص: الصندوق السري2الكائنات والأساليب
الـ Structs ككائناتمؤشر 'Self'صحة استخدام Constالمؤشر مقابل القيمةالأساليب المساعدةملخص: Point Manager5مشروع: حساب بنكي بسيط
إعداد المشروعتنفيذ الحساب3دورة حياة الكائن
نمط المنشئ (Constructor Pattern)نمط الهادم (Destructor Pattern)تهيئة الـ Stackالنسخ العميق (Deep Copy)مراجعة: String Wrapper6الوراثة عبر التركيب
تضمين الـ Structقاعدة العضو الأولالوصول إلى أعضاء الأبعملية الـ Upcastingمراجعة: هرمية الأشكال9مشروع: رسّام الأشكال
نظرة عامة على المشروعتنفيذ الدائرة