من «يُترجَم بنجاح» إلى «أستطيع قراءته»
في الصفحة السابقة أخذت ملف شفرة مصدرية وحوّلته إلى برنامج قابل للتشغيل باستخدام مترجِم. الآن سنتمهّل وننظر في ما كان موجودًا فعلًا في ذلك الملف. يُبنى كل برنامج C++ من الحفنة نفسها من القطع البنيوية، وبمجرد أن تتمكّن من تسميتها، يكفّ ملف .cpp غير المألوف عن أن يبدو مجرد ضجيج.
إليك برنامجًا كاملًا قابلًا للتشغيل. اقرأه مرة واحدة، ثم سنفكّكه سطرًا سطرًا.
خمسة أسطر ذات معنى، وكل واحد منها يؤدي وظيفة محدّدة. لنمرّ عليها واحدًا تلو الآخر.
سطر #include
#include <iostream>
يجلب هذا السطر الترويسة <iostream> حتى تتمكّن من استخدام ميزات الإدخال/الإخراج مثل cout. و#include هو توجيه للمعالج المسبق - يُنفَّذ قبل الترجمة الفعلية، وهو في جوهره يلصق محتوى تلك الترويسة في ملفك.
أمران يجعلان أسطر #include مميّزة:
- تبدأ بـ
#، وهذا ما يميّزها بوصفها توجيهات للمعالج المسبق. - لا تنتهي بفاصلة منقوطة. وهذا هو الاستثناء الشائع الوحيد من عادة «كل سطر ينتهي بـ
;» التي أنت على وشك اكتسابها.
إذا استخدمت cout ونسيت #include <iostream>، فلن يعرف المترجِم ما هو cout وستحصل على خطأ مثل 'cout' was not declared in this scope. والحل هو في الغالب الأعمّ إضافة include منسيّة.
دالة main
int main() {
// ...
return 0;
}
main هي حيث يبدأ برنامجك. عندما تشغّل البرنامج المُترجَم، يبدأ التنفيذ من أول سطر داخل main ويتوقّف عندما تُرجِع main قيمة. يحتوي كل برنامج C++ على دالة main واحدة بالضبط - لا أكثر ولا أقل.
المكوّنات:
int- تُعيدmainعددًا صحيحًا إلى نظام التشغيل. وبحسب العُرف، يعني0«اكتمل بنجاح».main()- الاسم، يتبعه قوسان للمعاملات (فارغان هنا).{ ... }- تحيط الأقواس المعقوفة بالجسم: الجُمل التي تُنفَّذ.return 0;- تُنهيmainوتُبلّغ عن النجاح. وإذا أغفلتها، تعامل C++ الدالةmainكأنها أعادت0نيابةً عنك - لكن كتابتها تجعل نيّتك واضحة.
الجُمل والفاصلة المنقوطة
الجملة هي تعليمة واحدة كاملة. في C++، تنتهي كل جملة بفاصلة منقوطة:
تتجاهل C++ فواصل الأسطر والمسافات الزائدة تجاهلًا تامًّا. لا يهمّ المترجِم إن وضعت الجُمل في سطر واحد أو في عشرة - فالـ ; هو ما يخبره أين تنتهي كل جملة. هذه الصيغ الثلاث متطابقة بالنسبة إلى المترجِم:
int a = 1; int b = 2;
int a = 1;
int b = 2;
int
a
= 1;
تأتي هذه الحرية مصحوبة بأكثر مزالق المبتدئين شيوعًا: فاصلة منقوطة منسيّة. انظر ماذا يحدث هنا.
int x = 5 // <-- بلا فاصلة منقوطة
int y = 10;
ستحصل على خطأ مثل expected ';' before 'int'. لاحظ الخدعة: لا يدرك المترجِم أنّ شيئًا ما خطأ إلا حين يصل إلى السطر التالي، لذا غالبًا ما يشير رقم السطر المُبلَّغ عنه إلى سطر أسفل الخطأ الحقيقي. عندما يذكر خطأ ما ; مفقودة، تحقّق من السطر الذي يعلو السطر المذكور في الرسالة.
الأقواس المعقوفة تحدّد الكتل
حيث تستخدم بعض اللغات الإزاحة لتجميع الشفرة، تستخدم C++ الأقواس المعقوفة { }. كل ما يقع بين زوج متطابق من الأقواس هو كتلة واحدة. وتستخدمها أجسام الدوال والحلقات والجُمل الشرطية if جميعها:
السطران داخل أقواس if يُنفَّذان فقط عندما يكون الشرط صحيحًا. أما آخر cout فهو خارج الأقواس، لذا يُنفَّذ دائمًا.
ولأن الأقواس المعقوفة - لا الإزاحة - هي التي تحدّد البنية، فإن C++ لا تُجبرك على الإزاحة. لكن ينبغي لك القيام بها على أي حال: فالإزاحة هي الطريقة التي يقرأ بها البشر البنية التي تحدّدها الأقواس. ومن الأخطاء الشائعة وجود قوس بلا قرين - فكل { يحتاج إلى } مُغلِق. وإذا نسيت واحدًا، يُبلّغ المترجِم عادةً عن خطأ قرب نهاية الملف (expected '}' at end of input)، بعيدًا عن المكان الذي زللت فيه فعلًا. وعدّ الأقواس، أو ترك المحرّر يطابقها لك، يوفّر عليك الكثير من الالتباس.
الإخراج بـ cout و<<
رأيت cout بضع مرات حتى الآن. إنه مجرى الإخراج القياسي، وترسل إليه القيم بالمُعامِل << (اقرأه على أنه «ضع هذا في الإخراج»):
يمكنك ربط عدة << معًا لطباعة أشياء عدة تباعًا. يُنهي endl السطر (كما يُفرِغ الذاكرة المؤقتة)؛ أما تسلسل الإفلات "\n" فهو طريقة أخفّ لطباعة سطر جديد. وفي البرامج البسيطة، كلاهما مناسب.
أما عن ذلك السطر using namespace std; في الأعلى: تقع أسماء المكتبة القياسية في فضاء الأسماء std، فيكون الاسم الكامل هو std::cout. وكتابة using namespace std; مرة واحدة تتيح لك إسقاط البادئة std:: وكتابة cout فقط. وهذا ملائم في الأمثلة القصيرة، لكن في المشاريع الكبيرة تُفضّل فرق كثيرة الصيغة الصريحة std::cout لتفادي تضارب الأسماء - فلا تتفاجأ برؤيته مكتوبًا بأيٍّ من الصيغتين.
أصبح بإمكانك الآن قراءة هيكل أي برنامج
تعليمات include في الأعلى، ودالة main بوصفها نقطة الدخول، وجُمل تنتهي بفواصل منقوطة، وأقواس تجمّع الشفرة في كتل، وcout << للإخراج - هذا الهيكل موجود في كل ملف C++ تقريبًا ستفتحه يومًا ما. وما تبقّى من اللغة تفاصيل مبنيّة فوق هذه الأشكال القليلة. وعندما يبدو برنامج ما مخيفًا، ابحث عن main أولًا، ثم اقرأ الجُمل بالترتيب؛ ستهديك البنية.
التالي: التعليقات
في الوقت الحالي، كل سطر في برامجك هو شفرة يقرأها المترجِم. وفي ما يلي سنضيف أسطرًا يتجاهلها المترجِم عن عمد - التعليقات - حتى تتمكّن من ترك ملاحظات لنفسك وللقرّاء الآخرين. سترى صيغة السطر الواحد // وصيغة الكتلة /* ... */، إضافةً إلى متى تكون كل منهما الخيار الصحيح.
الأسئلة الشائعة
لماذا تحتاج كل جملة في C++ إلى فاصلة منقوطة؟
تتجاهل C++ فواصل الأسطر والمسافات البيضاء، لذا تحتاج إلى علامة صريحة تبيّن أين تنتهي جملة وأين تبدأ التي تليها. هذه العلامة هي الفاصلة المنقوطة ;. ونسيان الفاصلة المنقوطة هو أكثر أخطاء الترجمة شيوعًا لدى المبتدئين، ورقم السطر المُبلَّغ عنه غالبًا ما يكون السطر الذي يلي السطر الذي نسيتها فيه.
ماذا تفعل ()int main في C++؟
main هي الدالة التي يبدأ منها تشغيل البرنامج؛ يبدأ التنفيذ من سطرها الأول وينتهي عندما تُرجِع قيمة. يحتاج كل برنامج C++ إلى دالة main واحدة بالضبط. ويعني int أنها تُعيد رمز حالة صحيحًا إلى نظام التشغيل، حيث يدلّ 0 على النجاح بحسب العُرف.
هل يجب أن أكتب std:: قبل cout؟
إما أن تكتب std::cout (بالاسم الكامل)، أو أن تضيف using namespace std; مرة واحدة في الأعلى ثم تكتب cout فقط. الصيغة الكاملة أكثر أمانًا في الملفات الكبيرة، أما using namespace std; فهو اختصار شائع في الأمثلة الصغيرة والدروس التعليمية.