الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Preprocessor Directives

بدأه time1 في 11 فبراير 2009 · 11 رد · 2,378 مشاهدة · في المواضيع والدروس
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

سأتكلم خلال هذا الدرس البسيط عن بعض المواضيع الموجودة في المرحلة التي تسبق الترجمة مثل : ادراج ملفات اخرى داخل الملف الحالي , تعريف عبارات ترجمة شرطية , تعريف ثوابت وماكرو وتنفيذ شرطي لما يسبق الترجمة .

التوجيهات التي تسبق مرحلة الترجمة Preprocessor Directives لاتعتبر تعليمات سي ++ , ولذلك لانجدها تنتهي بفاصلة منقوطة (; ) , ويتم معالجة هذه التوجيات قبل البدء بالترجمة .

اولا ً : include # :

يفيد هذا التوجيه في ادراج نسخة من ملف معين ضمن الملف الحالي , وهو على النحو التالي :

#include <filename>
#include "filename"

بحيث اذا تمت كتابة اسم الملف داخل علامتي < > فهذا يعني بان الملف المطلوب ادراجه موجود داخل مجلدات معروفة مسبقا ولها علاقة بمكتبات المترجم المعيارية .. مثل : iostream , iomanip

اما اذا تمت كتابة اسم الملف داخل علامتي " " فأن هذا يعني بأن الملف المراد ادراجه موجود داخل نفس المجلد الذي ينتمي إليه ملف البرنامج , عندها سيتم البحث عنه داخل هذا المجلد ثم ضمن المجلدات المعروفة مسبقا ً , وهذه الطريقة تستخدم لادراج الملفات المكتوبة بواسطة المبرمج .

ثانيا ً : الثوابت الرمزية :

يوجد لدينا ثوابت رمزية معرفة مسبقا ً , تبدء هذه الثوابت بعلامتي (_) وتنتهي بهما ايضا , مثل :

__FILE__ : سلسلة من الاحرف تمثل لنا اسم الملف المتضمن للبرنامج , مثال :

#include <iostream>
using namespace std;
int main ()
{
	cout<<__FILE__;//Print D:\test.cpp
  return 0;
}

__LINE__ : عدد صحيح يمثل رقم السطر ضمن نص البرنامج الحالي ,مثال :

#include <iostream>
using namespace std;
int main ()
{
	cout<<__LINE__;//Print 5
  return 0;
}

__STDC__ : عدد صحيح يدل على التوافق مع معايير ANSI (American National Standards Institute ) , مثال :

#if __STDC__

__DATE__ : سلسلة من الحروف تعيد لنا تاريخ ترجمة الملف على الصيغة Mmm dd yyyy , مثال :

#include <iostream>
using namespace std;
int main ()
{
	cout<<__DATE__;//Print Feb 11 2009
  return 0;
}

__TIME__ : سلسلة من الحروف تعيد لنا زمن ترجمة ملف البرنامج على الصيغة : hh:mm:ss , مثال :

#include <iostream>
using namespace std;
int main ()
{
	cout<<__TIME__;//Print 10:39:40
  return 0;
}

__TIMESTAMP__ : سلسلة حروف تمثل تاريخ وزمن اخر تعديل على ملف البرنامج بالصيغة : Ddd Mmm Date hh:mm:ss:yyyy

#include <iostream>
using namespace std;
int main ()
{
	cout<<__TIMESTAMP__;//Print Wed Feb 11 10:52:14 2009
  return 0;
}

ثالثا: Define #

وصيغته :

#define identifier replacement-text

عندما يظهر السطر السابق ضمن ملف فإنه يتم استبدال كافة الكلمات المطابقة لـ identifier بالسلسة : replacement-text بشكل اتوماتيكي قبل ان تتم الترجمة , مثلا :

#define PI 3.14159

رابعا: الماكرو .

وهو عبارة عن عملية معرفة باستخدام توجيه Define # وتماما مثل الثوابت السابقة يتم استبدال macro-identifier بالسلسلة replacement-text

#define PI 3.14159 
#define CIRCLE_AREA(x) (PI*(x)*(x))
int main ()
{
	cout<<CIRCLE_AREA(4);
  return 0;
}

من خلال المثال السابق : سيتم استبدال قيمة x ضمن العبارة المرافقة للماكرو .

ملاحظة : اذا تجاوزت التعليمات السطر الموافق لـ define وكنت ترغب بكتابتها على سطر اخر , قم باضافة العلامة (\) .

#define CIRCLE_AREA(x) (PI*(x)*(x\
))

ويتم استبعاد تعريف الماكرو او الثابت من خلال التعليمة undef # ,

#undef PI

خامسا ً : الترجمة الشرطية

وتشبه في هيكلها البنية if , على سبيل المثال :

#if !defined (NULL)
#define NULL 0
#endif

تفيد العبارة !defined في التحقق فيما اذا كانت القيمة NULL معرفة مسبقا ً ام لا , فإذا لم تكن معرفة يتم تعريفها واعطائها القيمة 0 .

يمكن ايضا استخدام التوجيهين : ifdef # والذي يعتبر اختصار للتوجيه

#if defined (name)

والتوجيه ifndef # والذي يعتبر اختصارا للتوجيه :

#if !defined (name)

ايضا يمكن استخدام التوجيه elif# المكافئ لـ else if في بنية if والتوجيه else # المكافئ لـ else في بنية if .

يمكننا ان نقوم بكتابة تعليقات لايتم ترجمتها من قبل المترجم بغير الطريقة /* و */ من خلال مرحلة ماقبل الترجمة , مثلا :

#if 0
cout<<"Code Prevented from compiling";
#endif

ولتنفيذ الكود السابق قم بتغيير القيمة 0 إلى القيمة 1 مثلاً .

سادسا ً : العمليتان # و ## .

* تقوم العملية # في تحويل وسيط ما إلى سلسلة حروف محاطة بعلامتين تنصين " " , مثلا ً :

#define HELLO(x) cout<<#x
int main ()
{
	HELLO("Ali");
  return 0;
}

*تقوم العملية ## بلصق وسطين من الماكرو مع بعضهما , مثلا ً :

#define CAT(x,y) x##y
int main ()
{
	cout<<CAT("Al-","Shammari")<<endl;
  return 0;
}

سادسا ً: ارقام الاسطر والتأكيدات .

* يمكن اعادة ترقيم الاسطر من خلال التوجيه line # ضمن نص البرنامج اعتبارا من القيمة الصحيحة المعطاة مع التوجيه , مثلا :

#include <iostream>
using namespace std;
int main ()
{
cout<<__LINE__<<endl;// Print 5
#line 100
	cout<<__LINE__<<endl;//Print 100
	cout<<__LINE__<<endl;// Print 101
  return 0;
}

وستكون المخرجات : 5- 100-101

* يقوم الماكرو assert بالتحقق من قيمة عبارة ما , فإذا كانت هذه القيمة مساوية للصفر يقوم الماكرو بطباعة رسالة خطأ وبعدها يستدعي الدالة abort من الملف ctdlib لانهاء تنفيذ البرنامج .

- يجب تضمين الملف cassert داخل ملف برنامجك .

مثلا : اذا اردنا ان يدخل المستخدم رقم الطالب بشرط ان يكون اكبر من 0 :

	int num;
	cin>>num;
	assert(num>0);
	cout<<num;

اتمنى ان اكون قد وفقت بهذا الدرس البسيط , مع تمنياتي لكم بالتوفيق .

1
llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#2

ما شاء الله ، شرح متميز جداً !!

وفقكم الله ،،

#3

جميل جدا عرضك مميز بارك الله فيك.

tvquran_6.gif

#4

معلومات جميلة، وعرض جميل، ودرس ممتاز..............

بارك الله فيك اخي الكريم

تم تعديل هذه المشاركة بواسطة mandareka في 11 فبراير 2009 في 15:25

دولة الخلافة الاسلامية في المخاض الاخير وميلادها قريب

حزب التحرير : التزم الطريق الصحيح الشرعي الوحيد لاعادة دولة الخلافة الاسلامية .

الامة الاسلامية متعطشة لقيادة مخلصة لتذوق حلاوة النصر ولن يكون ذلك الا بعودة الخلافة الاسلامية

الامة الاسلامية تحتاج لاحداث تسحقها سحقا وتمعسها معسا لتفكر تفكيرا جماعيا بالتغير لان وحدة المشاعر لوحدها لاتكفي وهذة الاحداث كلها خير

#5

السلام عليكم ,,

ما شاء الله مقال شامل

تك تك ...

تمت إضافته للمفضلة :)

#6

لى إستفسارات أخى time1 ،،

انا قرأت ذات مرة انه غير مفضل بالمرة الإعتماد على PreProcessor Directives ، هل هذا صحيح ؟؟

و قرأت ايضاً ، انه لا يجب الاعتماد على الـ Macros و يجب الاعتماد على الدوال ، لأن الـ Macros غير آمنة ، هل هذا صحيح ؟

و اذا كان كل هذا صحيح ، فما هو بديل كل اوامر الـ Preprocessor فى الأعلى ؟؟!! :)

#7
اقتباس
لى إستفسارات أخى time1 ،،

انا قرأت ذات مرة انه غير مفضل بالمرة الإعتماد على PreProcessor Directives ، هل هذا صحيح ؟؟

و قرأت ايضاً ، انه لا يجب الاعتماد على الـ Macros و يجب الاعتماد على الدوال ، لأن الـ Macros غير آمنة ، هل هذا صحيح ؟

و اذا كان كل هذا صحيح ، فما هو بديل كل اوامر الـ Preprocessor فى الأعلى ؟؟!!

مع أن السؤال ليس موجهاً لي, فليسمح الأخ time1 لي بالإجابة باختصار ...

أخ عمر,

هناك "بعض" الـ directives التي تم إيجاد بدائل أفضل بكثير لها ... و لكن لا مفر من استخدام الـ preprocessor في أي مشروع ..

الأمور التي لا تستطيع الإستغناء عنها أو لا يوجد لها بدائل هي :

تضمين الملفات include و الترجمة الشرطية هما الأكثر أهمية ..

و يأتي بعد ذلك الثوابت الرمزية....

لغة ANSI C تمكنك من تعريف الثوابت كما في ++C,

const int x = 0xA;

في السابق C لم تدعم هذا الأمر و لكن في المواصفات الحديثة ستجدها مدعومة و ذلك بدلاً من استخدام define...

لاحظ أن define في الترجمة الشرطية لا يمكن الاستغناء عنها, لأنها لا يتم استبدالها بالكود, و لكن فقط للتحكم بترجمة الكود...

بالطبع ++C هي التي وفرت هذا النوع من تعريف الثوابت و "C" اقتبسته منها حسبما أعرف..

إذا كنت تتكلم عن C فلا مفر من استخدام الـ Macro إذا كنت تريد الدوال inlined..

في ++C يمكنك تعريف الدالة على أنها inline و ذلك موجود في صميم اللغة على عكس C...

عموماً الـ Inlining في ++C يعطي نتائج أفضل, و راحة بال للمبرمج.. و أفضل خاصية برأيي أنك حينما تقوم بعملية التنقيح يمكنك المرور على الدوال الخطية في ++C كما لو أنها دوال عادية أما لو استخدمت الـ Macro فلن يتم التعامل معه على أنه دالة أصلاً.

يمكنك استخدام الـ templates لكتابة inline function تستطيع تقبل أي نوع كما هو الحال مع الـ Macro ..

تحياتي ,, و عذراً على التطفل :P

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 11 فبراير 2009 في 16:15

#8

جزاك الله خيراً أستاذنا

لكن هناك بعض النقاط التي لم أفهمها جيداً، سأطلعك عليها فيما بعد إن شاء الله، لعلك توضح لي ;)

جزاك الله خيراً :)

هذه الجملة خاطئة  :wacko: 


#9

المميز لايأتي منه الا كل مميز

وتعقيب بسيط للاخوان عليك ان تعرف ان يوجد خاصيات لابد تستعملها ومن بعدها ابدا براحتك في التفكير

لكم مني خالص التقدير

*********************

دروس الاكسس

قاعدة بيانات بالسي++

قاعدة بيانات اخرى بالسي++

الفريق العربي للبرمجه

*********************

كان الله في عون العبد مادام العبد في عون اخيه

#10

أكرر شكري لك أستاذ time1 والأستاذ خالد على توضيحه.

أعدت قراءة الدرس وفهمته بشكل عام، المشكلة أني لا أبرمج بـc++ بعد (لكن قريباً إن شاء الله) لكني فهمت المقصود.

شكراً لكم :)

هذه الجملة خاطئة  :wacko: 


#11
اقتباس
لى إستفسارات أخى time1 ،،

انا قرأت ذات مرة انه غير مفضل بالمرة الإعتماد على PreProcessor Directives ، هل هذا صحيح ؟؟

و قرأت ايضاً ، انه لا يجب الاعتماد على الـ Macros و يجب الاعتماد على الدوال ، لأن الـ Macros غير آمنة ، هل هذا صحيح ؟

و اذا كان كل هذا صحيح ، فما هو بديل كل اوامر الـ Preprocessor فى الأعلى ؟؟!!

اولا اشكر اخي واستاذي Khaled.Alshaya , ماشاء الله عليه كفى ووفا :rolleyes:

ثانيا , نعم هناك بعض المراجع والكتب التي تقول بأن استخدام PreProcessor غير مفضل , لكن ثق تماما بأن الامر يعتمد على حسب الحاجة , اي احيانا يعتبر استخدام PreProcessor من الذكاء .

ايضا الـ PreProcessor تلائم مبرمجين السي , ( وخاصة الماكرو ) , اكثر من مبرمجي السي ++ , لكن هذا لايعني ان مبرمج السي ++ بغنى عنها , فقد يحتاج احيانا للتعامل مع برامج مكتوبة بلغة سي .

طبعا يوجد بدائل لكن لاتعتبر ان هذا من المميزات , على سبيل المثال , دائما تجد مراجع السي ++ تفضل استخدام const على الثوابت الرمزية define ,وذلك لان لها نمط( نوع ) محدد , بالاضافة لانها مرئية من خلال اسمائها من قبل الـ debugger , لكن لاننسى الفرق بينهما من ناحية الذاكرة , فـ define لايتم لها حجز بالذاكرة , وانما يتم استبدال الidentifier بـ replacement-text حالما يجده , على عكس الـ const التي تقوم بالحجز داخل الذاكرة , وعند استدعاء المتغير سيتم استدعائه من الذاكرة .

Abboodd , حياك الله في اي وقت .

الاخوة فهد وخالد و عبدالهادي وعمر العادل و mandareka , اشكركم من اعماق قلبي على ردودكم التي ابهجتني .

تحياتي .

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#12

أشكرك أخى خالد على الشرح الممتاز ،، حياك الله :)

أشكرك مرة اخرى :) أخى time1 على شرحك المتميز :)

وفقكم الله ،،

مواضيع مشابهة