Menu
flag Ar iconالعربيةdown icon

صياغة لغة C: شرح بنية برنامج C

لكل برنامج C الهيكل نفسه: التضمينات، ودالة main، وجمل تنتهي بفواصل منقوطة، وكتل بين أقواس معقوفة. إليك ما يفعله كل جزء والقواعد التي يفرضها المترجم فعليًا.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

تحوي لغة C صياغة قليلة جدًا للتعلّم - نحو 32 كلمة مفتاحية وحفنة من قواعد الترقيم. وتقريبًا كل برنامج ستكتبه يومًا له الشكل الخارجي نفسه، لذا يستحقّ ذلك الشكل أن نفكّكه مرة واحدة بعناية.

أصغر برنامج كامل

هذا يُترجَم ويعمل ولا يفعل شيئًا:

لا تضمينات، ولا مخرجات، ولا صنف أو وحدة نمطية إلزامية. main هي نقطة الدخول: فحين يشغّل نظام التشغيل برنامجك، يستدعي main. وحين تعود main ينتهي البرنامج، والقيمة التي تعيدها هي حالة الخروج.

أضف مخرجات فتحتاج إلى تضمين واحد:

توجيهات المعالج الأولي

الأسطر التي تبدأ بـ # يعالجها المعالج الأولي قبل الترجمة الفعلية. وهي ليست جمل C، ولا تأخذ فاصلة منقوطة.

#include <stdio.h>    /* ترويسة من المكتبة القياسية - أقواس زاوية */
#include "myutils.h"  /* ترويستك أنت - علامات اقتباس، يُبحث محليًا أولًا */
#define MAX 100       /* ماكرو - تُستبدل MAX بـ 100 في كل ما تحتها */

#include لصق نصّي حرفي: فتُسقَط محتويات الملف المسمّى بأكملها عند تلك النقطة. ويحتوي stdio.h على تصريح printf، وبه يعرف المترجم الوسائط التي تأخذها printf. احذف التضمين فتحصل على implicit declaration of function 'printf'.

والفرق بين الأقواس الزاوية وعلامات الاقتباس يتعلّق بموضع بحث المترجم: <...> تعني أدلّة التضمين النظامية، و"..." تعني ابحث بجوار هذا الملف أولًا.

دالة main

int main(void) {
    return 0;
}

أربعة أجزاء، كل منها ذو معنى:

  • int - نوع إرجاع main. تذهب القيمة إلى نظام التشغيل كحالة خروج، حيث يعني 0 النجاح.
  • main - الاسم المحجوز الذي تستدعيه بيئة التشغيل. ولكل برنامج C مستضاف واحدة بالضبط.
  • (void) - قائمة الوسائط. وvoid هنا تعني "لا تأخذ أي وسائط". أما كتابة main() فمسموحة لكنها أضعف: فالقوسان الفارغان في C يعنيان "وسائط غير محدّدة"، وهو ما يعطّل فحص الوسائط.
  • { ... } - جسم الدالة.

والصيغة القياسية الأخرى تأخذ وسائط سطر الأوامر:

int main(int argc, char *argv[]) { ... }

استخدم int main(void) حتى تحتاج إليها.

الجمل والفواصل المنقوطة

الجملة تعليمة واحدة، وتنتهي بفاصلة منقوطة.

أربع جمل، وأربع فواصل منقوطة. والفاصلة المنقوطة مُنهية لا فاصلة - فالجملة الأخيرة في الكتلة تحتاج إليها أيضًا.

وما لا يأخذ فاصلة منقوطة:

#include <stdio.h>        /* سطر معالج أولي - بلا فاصلة منقوطة */

int add(int a, int b) {   /* ترويسة تعريف دالة - بلا فاصلة منقوطة */
    return a + b;
}                         /* القوس الخاتم لدالة - بلا فاصلة منقوطة */

if (x > 0) {
    ...
}                         /* القوس الخاتم لكتلة تحكّم - بلا فاصلة منقوطة */

والحالة الوحيدة التي توقع الجميع هي فاصلة منقوطة في موضع الجسم:

if (score > 90);              /* BUG: this ; is the entire if body */
    printf("Excellent!\n");   /* always runs, whatever score is */

هذه صياغة C سليمة تمامًا. فـ if تتحكّم بجملة فارغة، وprintf ليست سوى السطر التالي في التسلسل. ينبّهك -Wall إليها؛ أما المترجم فلن يوقفك.

الكتل والأقواس المعقوفة

تجمّع الأقواس المعقوفة الجمل في كتلة، تُعدّ جملة واحدة في كل موضع تُتوقَّع فيه جملة.

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

كما تُنشئ الكتل نطاقًا: فمتغيّر معرَّف داخل { ... } يتوقّف عن الوجود عند القوس الخاتم.

حساسية حالة الأحرف والمسافات

لغة C حسّاسة لحالة الأحرف في كل مكان. فـ total وTotal وTOTAL ثلاثة أسماء منفصلة. وكل كلمة مفتاحية بأحرف صغيرة، لذا فإن Int وReturn وPrintf كلها أخطاء - ورسالة الخطأ الخاصة بـ Printf محيّرة، لأن المترجم يفترض أنك قصدت دالة لم يسمع بها قطّ.

أما المسافات فحرّة تقريبًا بالكامل. يعامل المترجم أي سلسلة من المسافات والجدولات والأسطر الجديدة كفاصل واحد. هذا صالح:

int    main ( void )
{
    printf
    ( "Hello\n" ) ;
    return 0 ;
}

وكذلك هذا:

int main(void){printf("Hello\n");return 0;}

كلاهما يُترجَم بالشكل نفسه تمامًا. وبما أن المترجم لا يأبه، فإن التنسيق للبشر وحدهم - والتخطيط التقليدي (جملة واحدة لكل سطر، وأربع مسافات أو جدولة واحدة لكل مستوى تداخل، والقوس الفاتح في السطر نفسه) يستحقّ الاتباع لأن كل قاعدة شيفرة C ستقرؤها ستستخدم شيئًا قريبًا منه.

وثمّة موضعان تهمّ فيهما المسافات: لا يمكنك تقسيم كلمة مفتاحية أو معرّف (in t ليست int)، ولا يمكنك وضع سطر جديد داخل سلسلة نصية عادية.

المعرّفات: قواعد التسمية

المعرّف هو أي اسم تختاره - للمتغيّرات والدوال والأنواع. والقواعد:

  • يتكوّن من حروف وأرقام وشرطات سفلية.
  • يجب ألّا يبدأ برقم. total2 جيد، و2total ليس كذلك.
  • لا يجوز أن يكون كلمة مفتاحية: فلا متغيّر باسم int أو for أو return.
  • حالة الأحرف مهمّة.
  • الأسماء التي تبدأ بشرطة سفلية، وأي اسم فيه شرطتان سفليتان متتاليتان، محجوزة للتطبيق - فلا تخترعها.
int score;        /* جيد */
int total_items;  /* جيد - snake_case هو عُرف C */
int _hidden;      /* مسموح لكنه محجوز - تجنّبه */
int 2fast;        /* خطأ */
int float;        /* خطأ - كلمة مفتاحية */

برنامج موثّق بالكامل

كل ما سبق، في مكان واحد:

ترتيب القراءة مهمّ هنا: فـ with_tax معرَّفة قبل أن تستخدمها main. تقرأ C الملف من أعلى إلى أسفل، لذا يجب التصريح عن الدالة قبل استدعائها. عرّفها قبل ذلك، أو اكتب نموذج دالة في الأعلى وعرّفها لاحقًا.

الأسئلة الشائعة

ما البنية الأساسية لبرنامج C؟

توجيهات المعالج الأولي أولًا (#include <stdio.h>)، ثم تعريفات الدوال، وإحداها يجب أن تكون main. وداخل الدالة تنتهي الجمل بفواصل منقوطة وتُحاط الكتل بأقواس معقوفة. وأصغر برنامج هو #include <stdio.h> مع int main(void) { return 0; }.

لماذا نكتب int main(void) وليس main() فقط؟

int هو نوع إرجاع main - أي حالة الخروج التي يسلّمها البرنامج لنظام التشغيل. و(void) تقول صراحةً إن main لا تأخذ أي وسائط. أما كتابة main() بقوسين فارغين فأسلوب أقدم لا يخبر المترجم شيئًا عن الوسائط، فيقلّ فحصه.

هل تحتاج كل جمل C إلى فاصلة منقوطة؟

كل جملة تحتاجها، لكن ليس كل سطر. فتوجيهات المعالج الأولي (#include و#define) وتعريفات الدوال والقوس المعقوف الخاتم لكتلة أو لـ if/for/while لا تأخذ واحدة. وفاصلة منقوطة شاردة بعد if (x) صياغة C سليمة تجعل الجسم يُنفَّذ دون شرط بصمت.

هل تفرّق لغة C بين الأحرف الكبيرة والصغيرة؟

نعم، تمامًا. count وCount وCOUNT ثلاثة معرّفات مختلفة، وInt ليست الكلمة المفتاحية int. وكل كلمات C المفتاحية بأحرف صغيرة، فحرف كبير في Return أو Printf يُنتج خطأً.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن