حواجز التضمين
امنع التضمين المزدوج
حواجز التضمين درس مجاني في C Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.
مشكلة التضمين المزدوج
غالبًا ما تضمّن الترويسات ترويسات أخرى. ومن السهل أن ينتهي الأمر بتضمين ترويسة واحدة مرتين في ملف المصدر نفسه.
عند حدوث ذلك، يظهر كل تصريح فيها مرتين. وبالنسبة إلى تعريفات الأنواع مثل struct أو typedef، فهذا خطأ في الترجمة؛ إذ لا يمكن تعريف النوع أكثر من مرة.
كيف يحدث ذلك دون أن تلاحظه
افترض أن a.h وb.h يضمّنان كلاهما types.h. سينتهي ملف المصدر الذي يضمّنهما معًا إلى إدراج types.h مرتين.
ينسخ المعالج المسبق نص الترويسة دون تحقق، لذلك تتكرر تعريفات types.h، مما يؤدي إلى خطأ إعادة التعريف.
/* a.h */ #include "types.h"
/* b.h */ #include "types.h"
/* main.c */
#include "a.h"
#include "b.h" /* types.h now seen twice */حارس التضمين
حارس التضمين حيلة صغيرة للمعالج المسبق تجعل الترويسة آمنة عند تضمينها مرات عديدة.
فهو يحيط بالترويسة كاملةً بشرط، بحيث تتم معالجة محتواها في المرة الأولى فقط. أما عمليات التضمين اللاحقة فتُتخطى بالكامل.
#ifndef TYPES_H
#define TYPES_H
/* header contents here */
#endif /* TYPES_H */كيفية عمل الحارس
في المرة الأولى التي تُقرأ فيها الترويسة، لا يكون TYPES_H معرّفًا، لذلك يكون شرط #ifndef صحيحًا وتتم معالجة المحتوى. ثم يعرّف #define الماكرو.
في أي تضمين لاحق، يكون TYPES_H موجودًا بالفعل، لذلك يكون شرط #ifndef خاطئًا ويتخطى المعالج المسبق كل شيء حتى #endif.
#ifndef TYPES_H /* true only the first time */
#define TYPES_H /* remember we've been here */
/* ... body ... */
#endifترويسة محمية كاملة
إليك ترويسة واقعية يحمي فيها حارسٌ تعريفَ نوع.
حتى إذا ضمّنت ملفات عديدة point.h مباشرةً أو بطريقة غير مباشرة، فسيُعرّف الهيكل Point مرة واحدة فقط في كل وحدة ترجمة.
/* point.h */
#ifndef POINT_H
#define POINT_H
typedef struct {
int x;
int y;
} Point;
Point point_add(Point a, Point b);
#endifاختيار اسم الماكرو
يجب أن يكون ماكرو الحارس فريدًا على مستوى مشروعك بالكامل، وإلا فقد تتعارض ترويستان وتحجب إحداهما الأخرى دون تنبيه.
من الأعراف الشائعة اشتقاق الاسم من اسم الملف بأحرف كبيرة: يصبح point.h هو POINT_H، ويصبح net/socket.h هو NET_SOCKET_H.
#ifndef NET_SOCKET_H
#define NET_SOCKET_H
/* ... */
#endifتجنب الأسماء المحجوزة
تُحجز للمعالج المسبق والمكتبة القياسية المعرفات التي تبدأ بشرطة سفلية تليها أحرف كبيرة، أو التي تحتوي على شرطتين سفليتين متتاليتين.
تجنب حواجز مثل __POINT_H__. أما الصيغة البسيطة المنتهية مثل POINT_H فهي آمنة وواضحة.
#ifndef _POINT_H_ /* risky: reserved name pattern */
#ifndef POINT_H /* preferred */بديل #pragma once
تدعم معظم المصرّفات الحديثة #pragma once، وهو سطر واحد في أعلى الترويسة يؤدي المهمة نفسها.
يتميز هذا البديل بقصره وتجنبه تعارضات الأسماء، لكنه ليس جزءًا من معيار C. أما حواجز #ifndef التقليدية فتعمل في كل مكان.
/* point.h */
#pragma once
typedef struct { int x; int y; } Point;الحواجز مقابل pragma
حواجز #ifndef محمولة بالكامل وقياسية، لكنها تتطلب ماكرو فريدًا لكل ترويسة.
تتميز #pragma once بالاختصار وعدم التسبب في تعارضات، لكنها تعتمد على دعم المصرّف. وتستخدم بعض المشاريع كليهما: pragma مع حارس تقليدي لتحقيق أقصى قدر من الأمان.
#pragma once
#ifndef POINT_H
#define POINT_H
/* ... */
#endifالحواجز خاصة بكل وحدة ترجمة
يمنع حارس التضمين التضمين المكرر داخل ملف مصدر واحد أثناء ترجمته.
لكنه لا يمنع معالجة الترويسة مرة واحدة في كل ملف .c منفصل. وهذا أمر طبيعي، لأن كل ملف مصدر يمثل وحدة ترجمة مستقلة.
اجعل ذلك عادة
أضف حارس تضمين إلى كل ترويسة تكتبها، بدءًا من السطر الأول. فهو لا يكلف سوى ثلاثة أسطر، ويمنع فئة كاملة من الأخطاء المربكة.
حتى الترويسات البسيطة قد تُضمّن لاحقًا بطريقة غير مباشرة عبر ترويسات أخرى، لذلك يوفر الحارس منذ البداية كثيرًا من المتاعب.
/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
#define MAX_USERS 100
#endifتحقق سريع
تحقق من مدى استيعابك لحواجز التضمين.
مراجعة
تعلمت سبب تسبب تضمين الترويسة مرتين في أخطاء إعادة التعريف، وكيف يمنع حارس التضمين ذلك.
استخدم #ifndef/#define/#endif مع ماكرو فريد، أو استخدم #pragma once. سننظر لاحقًا في مشاركة المتغيرات بين الملفات باستخدام extern.
الأسئلة الشائعة
هل درس «حواجز التضمين» مجاني؟
نعم — نص درس «حواجز التضمين» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.
ماذا ستتعلم في «حواجز التضمين»؟
امنع التضمين المزدوج تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟
لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «حواجز التضمين»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟
نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.