English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

دروس أساسية لغة C

تحكم في تدفق لغة C

الوظائف في لغة C

المسافات في لغة C

المراجع في لغة C

النصوص في لغة C

مباني لغة C

ملف لغة C

C أخرى

دليل مرجعي للغة C

المعالج المسبق (Preprocessor) في لغة C

في هذا الدرس، سنقدم لك معالج البرمجة في C، وسنتعلم باستخدام #include، #define وتحليل الشروط المسبقة في أمثلة.

معالج البرمجة في Cليس جزءًا من معالج البرمجة، ولكن هو خطوة منفصلة في عملية البرمجة. باختصار، معالج البرمجة في C هو أداة استبدال النص فقط، التي ستشير إلى معالج البرمجة للقيام بما يلزم قبل البرمجة الفعلية. سنقوم بتسمية معالج البرمجة في C (C Preprocessor) بـ CPP.

جميع أوامر المعالج المسبق تبدأ بمعرف ( #( )). يجب أن يكون هذا المعرف أول رمز غير فارغ، من أجل تحسين القدرة على القراءة، يجب أن تبدأ أوامر المعالج المسبق من الصف الأول. يُظهر لنا ما يلي جميع الأوامر المهمة لمعالج المعالج المسبق:

الأمرالوصف
#defineتعريف الماكرو
#includeتضمين ملف مصدر
#undefإلغاء تعريف الماكرو المحدد
#ifdefإذا تم تعريف الماكرو، يتم العودة إلى الحقيقة
#ifndefإذا لم يتم تعريف الماكرو، يتم العودة إلى الحقيقة
#ifإذا كانت الشروط المقدمة صحيحة، يتم تجميع الكود أدناه
#elseبديل #if
#elifإذا كانت الشروط المقدمة سابقاً غير صحيحة، والشروط الحالية صحيحة، يتم تجميع الكود أدناه
#endifتنتهي من مكتبة تعديل شرطية #if……#else
#errorعند مواجهة خطأ معياري، يتم عرض رسالة الخطأ.
#pragmaاستخدام طريقة معيارية، ننشر أوامر خاصة إلى معالج البرمجة

مثال معالج البرمجة

تحليل المثال أدناه لفهم الأوامر المختلفة.

#define MAX_ARRAY_LENGTH 20

هذا الأمر يخبر CPP بتبديل كل MAX_ARRAY_LENGTH إلى 20. باستخدام #define تعريف القيم الثابتة لتحسين القدرة على القراءة.

#include <stdio.h>
#include "myheader.h"

هذه الأوامر تخبر CPP للحصول علىالمكتبة النظاميةالحصول على stdio.h من الدليل الحالي، ويضيف النص إلى الملف المصدر الحالي. الخط التالي يخبر CPP للحصول على myheader.h، ويضيف محتوى إلى الملف المصدر الحالي.

#undef FILE_SIZE
#define FILE_SIZE 42

تخبر هذه التعليمات CPP إلغاء تعريف FILE_SIZE المحدد مسبقًا، وتعريفه كـ 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

تخبر هذه التعليمات CPP إذا لم يتم تعريف MESSAGE، يتم تعريف MESSAGE.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

تخبر هذه التعليمات CPP إذا كان DEBUG معرفًا، يتم تنفيذ التعليمات المعالجة. عند التجميع، إذا كنت قد نقلت إلى معالج GCC -DDEBUG مفتاح التشغيل، هذه التعليمات مفيدة جدًا. يحدد DEBUG، يمكنك تشغيل أو إيقاف التتبع في أي وقت خلال التجميع.

الماكرو المحددة مسبقًا

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

الماكروالوصف
__DATE__التاريخ الحالي، كمية نصية ثابتة تُعبر عنها بـ "MMM DD YYYY".
__TIME__الوقت الحالي، كمية نصية ثابتة تُعبر عنها بـ "HH:MM:SS".
__FILE__سيكون هذا يحتوي على اسم الملف الحالي، كمية نصية ثابتة.
__LINE__سيكون هذا يحتوي على رقم السطر الحالي، كمية ثابتة عشرية.
__STDC__عندما يتم تجميع الماكرو بمعيار ANSI، يتم تعريفه كـ 1.

لنحاول الآن مثالًا تحتويًا على:

#include <stdio.h>
main()
{
   printf("الملف :%s\n", __FILE__);
   printf("التاريخ :%s\n", __DATE__);
   printf("الوقت :%s\n", __TIME__);
   printf("السطر :%d\n", __LINE__);
   printf("ANSI :%d\n", __STDC__);
}

عندما يتم تجميع الكود (في ملف test.c عندما يتم تجميع وتنفيذ) ينتج النتيجة التالية:

الملف :test.c
التاريخ :Jun 2 2012
الوقت :03:36:24
السطر :8
ANSI :1

عميل معالج

يقدم معالج C التالي العمليات المساعدة لإنشاء الماكرو:

عميل التمديد الماكرو (\)

عادة ما يكتب الماكرو على سطر واحد. ولكن إذا كان الماكرو طويلاً غير قادر على احتواءه على سطر واحد، يتم استخدام عميل التمديد الماكرو (\). على سبيل المثال:

#define message_for(a, b) \"
    printf(#a " and " #b ": We love you!\n")

字符串常量化运算符(#)

في التعريف الماكرو، عند الحاجة إلى تحويل معامل الماكرو إلى متغير نصي ثابت، يتم استخدام عميل التبديل النصي الثابت (#). ويكون لديه هذا العميل معامل معين أو قائمة من المعاملات في الماكرو. على سبيل المثال:

#include <stdio.h>
#define message_for(a, b) \"
    printf(#a " and " #b ": We love you!\n")
int main(void)
{
   message_for(Carole, Debra);
   return 0;
}

عندما يتم ترميز وتشغيل الكود أعلاه، سيتم توليد النتيجة التالية:

Carole and Debra: We love you!

标记粘贴运算符(##)

宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。例如:

#include <stdio.h>
#define tokenpaster(n) printf("token" #n " = %d", token##n)
int main(void)
{
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}

عندما يتم ترميز وتشغيل الكود أعلاه، سيتم توليد النتيجة التالية:

token34 = 40

这是怎么发生的,因为这个示例会从编译器产生下列的实际输出:

printf("token34 = %d", token34);

这个示例演示了 token##n 会连接到 token34 中,在这里,我们使用了字符串常量化运算符(#)标记粘贴运算符(##)

defined() 运算符

预处理器 defined 运算符是用在常量表达式中的,用来确定一个标识符是否已经使用 #define 定义过。如果指定的标识符已定义,则值为真(非零)。如果指定的标识符未定义,则值为假(零)。下面的示例演示了 defined() 运算符的用法:

#include <stdio.h>
#if !defined(MESSAGE)
   #define MESSAGE "You wish!"
#endif
int main(void)
{
   printf("这是消息: %s\n", MESSAGE);  
   return 0;
}

عندما يتم ترميز وتشغيل الكود أعلاه، سيتم توليد النتيجة التالية:

这是消息: You wish!

参数化的宏

CPP 一个强大的功能是可以使用参数化的宏来模拟函数。例如,下面的代码是计算一个数的平方:

int square(int x) {
   return x * x;
}

我们可以使用宏重写上面的代码,如下:

#define square(x) ((x) * (x))

在使用带有参数的宏之前,必须使用 #define 指令定义。参数列表是括在圆括号内,且必须紧跟在宏名称的后边。宏名称和左圆括号之间不允许有空格。例如:

#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{
   printf("أكبر قيمة بين 10 و 20 هي %d\n", MAX(10, 20));  
   return 0;
}

عندما يتم ترميز وتشغيل الكود أعلاه، سيتم توليد النتيجة التالية:

أكبر قيمة بين 10 و 20 هي 20