هل كانت مفيدة؟

المحلول

قيمة الإرجاع ل main يجب أن تشير إلى كيفية خروج البرنامج.يتم تمثيل الخروج العادي بشكل عام بقيمة إرجاع 0 من main.عادة ما تتم الإشارة إلى الخروج غير الطبيعي من خلال عودة غير الصفر، ولكن لا يوجد معيار لكيفية تفسير الرموز غير الصفرية.كما لاحظ آخرون، void main() محظور بشكل صريح بواسطة معيار C++ ولا ينبغي استخدامه.C++ صالح main التوقيعات هي:

int main()

و

int main(int argc, char* argv[])

وهو ما يعادل

int main(int argc, char** argv)

ومن الجدير بالذكر أيضًا أنه في لغة C++، int main() يمكن تركه بدون بيان إرجاع، وعند هذه النقطة يتم إرجاع 0 افتراضيًا.وينطبق هذا أيضًا على برنامج C99.سواء return 0; يجب حذفها أم لا فهي مفتوحة للنقاش.نطاق التوقيعات الرئيسية لبرنامج C الصالحة أكبر بكثير.

كما أن الكفاءة ليست مشكلة في main وظيفة.يمكن إدخاله وتركه مرة واحدة فقط (مع تحديد بداية البرنامج وإنهائه) وفقًا لمعيار C++.بالنسبة لـ C، الحالة مختلفة وإعادة الدخول main() مسموح به، ولكن ينبغي تجنبه.

نصائح أخرى

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

ISO/IEC 9899:1989 (C90):

main() يجب الإعلان عنها إما:

int main(void)
int main(int argc, char **argv)

أو ما يعادلها.على سبيل المثال، int main(int argc, char *argv[]) يعادل الثاني.علاوة على ذلك، int يمكن حذف نوع الإرجاع لأنه افتراضي.

إذا سمح التنفيذ بذلك، main() يمكن الإعلان عنها بطرق أخرى، ولكن هذا يجعل تنفيذ البرنامج محددًا، ولم يعد مطابقًا بشكل صارم.

يحدد المعيار 3 قيم للعودة التي تتوافق تمامًا (أي لا تعتمد على السلوك المحدد للتنفيذ): 0 و EXIT_SUCCESS لإنهاء ناجح، و EXIT_FAILURE لإنهاء غير ناجح.أي قيم أخرى غير قياسية ويتم تحديد التنفيذ. main() يجب أن يكون صريحا return بيان في النهاية لتجنب السلوك غير المحدد.

أخيرًا، لا حرج من وجهة نظر المعايير في الاتصال main() من برنامج.

ISO/IEC 9899:1999 (C99):

بالنسبة لـ C99، كل شيء هو نفسه كما هو مذكور أعلاه باستثناء:

  • ال int لا يجوز حذف نوع الإرجاع.
  • يمكنك حذف بيان الإرجاع من main().إذا قمت بذلك، و main() انتهى، هناك ضمنا return 0.

المعيار ج - البيئة المستضافة

بالنسبة للبيئة المستضافة (هذه هي البيئة العادية)، يقول معيار C11 (ISO/IEC 9899:2011):

5.1.2.2.1 بدء تشغيل البرنامج

تتم تسمية الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج main.يعلن التنفيذ لا نموذج أولي لهذه الوظيفة.يجب أن يتم تعريفه بنوع الإرجاع int وبدون البارامترات:

int main(void) { /* ... */ }

أو مع معلمتين (يشار إليهما هنا باسم argc و argv, ، على الرغم من أن أي أسماء قد تكون كذلك تستخدم ، لأنها محلية للوظيفة التي يتم الإعلان عنها):

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

أو ما يعادلها؛10) أو بطريقة أخرى محددة للتنفيذ.

إذا تم الإعلان عنها ، يجب أن تطيع المعلمات للوظيفة الرئيسية ما يلي القيود:

  • قيمة ال argc يجب أن تكون غير سلبية.
  • argv[argc] يجب أن يكون مؤشرًا فارغًا.
  • إذا كانت قيمة argc أكبر من الصفر، أعضاء المصفوفة argv[0] خلال argv[argc-1] يجب أن تحتوي على مؤشرات للسلاسل، والتي تعطى القيم المحددة للتنفيذ من قبل البيئة المضيفة قبل بدء تشغيل البرنامج.القصد من ذلك هو تزويد البرنامج بالمعلومات المحددة قبل بدء تشغيل البرنامج من مكان آخر في البيئة المستضافة.إذا كانت البيئة المضيفة غير قادرة على تزويد السلاسل بأحرف كبيرة وصغيرة، يجب التأكد من استلام السلاسل بحروف صغيرة.
  • إذا كانت قيمة argc أكبر من الصفر، السلسلة المشار إليها بواسطة argv[0]يمثل اسم البرنامج. argv[0][0] يجب أن يكون الحرف الفارغ إذا كان اسم البرنامج غير متاح من بيئة المضيف.إذا كانت قيمة argc أكبر من واحد، تشير الأوتار إلى argv[1] خلال argv[argc-1]تمثل معلمات البرنامج.
  • المعلمات argc و argv والسلاسل التي أشار إليها argv يجب أن تكون الصفيف تكون قابلة للتعديل بواسطة البرنامج ، والاحتفاظ بقيمها المخزنة الأخيرة بين البرنامج بدء التشغيل وإنهاء البرنامج.

10) هكذا، int يمكن استبداله باسم typedef المحدد كـ int, ، أو نوعه argv يمكن كتابتها كما char **argv, ، وما إلى ذلك وهلم جرا.

إنهاء البرنامج في C99 أو C11

القيمة التي تم إرجاعها من main() يتم نقله إلى "البيئة" بطريقة محددة بالتنفيذ.

5.1.2.2.3 إنهاء البرنامج

1 إذا كان نوع الإرجاع main الدالة هي نوع متوافق مع int, ، عائد من مكالمة أولية إلى main الدالة تعادل استدعاء exit الدالة مع القيمة التي تم إرجاعها بواسطة main تعمل كحجة لها؛11) الوصول إلى } الذي ينهي main ترجع الدالة قيمة 0.إذا كان نوع الإرجاع غير متوافق مع int, ، حالة الإنهاء التي تم إرجاعها إلى بيئة المضيف غير محددة.

11) وفقًا للفقرة 6.2.4، تم الإعلان عن عمر الكائنات ذات مدة التخزين التلقائي mainسيكون قد انتهى في الحالة الأولى، حتى لو لم يكن الأمر كذلك في الحالة الأخيرة.

لاحظ أن 0 تم تكليفه بـ "النجاح".يمكنك استخدام EXIT_FAILURE و EXIT_SUCCESS من <stdlib.h> إذا كنت تفضل ذلك، ولكن 0 راسخ، وكذلك 1.أنظر أيضا رموز الخروج أكبر من 255 — ممكن؟.

في C89 (وبالتالي في Microsoft C)، لا يوجد بيان حول ما يحدث إذا كان main() ترجع الدالة ولكنها لا تحدد قيمة الإرجاع؛وبالتالي فإنه يؤدي إلى سلوك غير محدد.

7.22.4.4 exit وظيفة

¶5 أخيرًا، يتم إرجاع التحكم إلى البيئة المضيفة.إذا كانت قيمة status هو صفر أو EXIT_SUCCESS, ، وهو شكل محدد من التنفيذ للحالة الإنهاء الناجح يتم إرجاع.إذا كانت قيمة status يكون EXIT_FAILURE, ، وهو شكل محدد من التنفيذ للحالة إنهاء غير ناجح يتم إرجاع.وإلا فإن الحالة التي تم إرجاعها تكون محددة بالتنفيذ.

معيار C++ - بيئة مستضافة

يقول معيار C++11 (ISO/IEC 14882:2011):

3.6.1 الوظيفة الرئيسية [basic.start.main]

¶1 يجب أن يحتوي البرنامج على دالة عامة تسمى main، وهي البداية المحددة للبرنامج.[...]

¶2 يجب ألا يحدد التنفيذ الوظيفة الرئيسية مسبقًا.لا يجوز تحميل هذه الوظيفة بشكل زائد.وعليها أن لديك نوع إرجاع من النوع int ، ولكن بخلاف ذلك يتم تحديد نوعه للتنفيذ.يجب أن تسمح جميع عمليات التنفيذ بكلا التعريفين التاليين للتعريف الرئيسي:

int main() { /* ... */ }

و

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

في الشكل الأخير argc يجب أن يكون عدد الحجج التي تم تمريرها إلى البرنامج من البيئة التي يتم فيها تشغيل البرنامج.لو argc غير صفرية، يجب توفير هذه الوسائط argv[0]خلال argv[argc-1] كمؤشرات للأحرف الأولية لسلاسل متعددة البايت منتهية بقيمة خالية (NTMBSs) (17.5.2.1.4.2) و argv[0] يجب أن يكون مؤشرًا على الحرف الأولي لـ NTMBS الذي يمثل الاسم المستخدم لاستدعاء البرنامج أو "".قيمة ال argc أن تكون غير سلبية.قيمة ال argv[argc]يجب أن يكون 0.[ ملحوظة:يوصى بإضافة أي معلمات أخرى (اختيارية) بعد ذلك argv.*نهاية الملاحظة*

¶3 الوظيفة main لا يجوز استخدامها داخل البرنامج.الربط (3.5) من main يتم تحديد التنفيذ.[...]

¶5 بيان الإرجاع بشكل رئيسي له تأثير ترك الوظيفة الرئيسية (تدمير أي كائنات أوتوماتيكية مدة التخزين) والاتصال std::exit مع قيمة الإرجاع كوسيطة.إذا وصل التحكم إلى النهاية الرئيسية دون مواجهة بيان الإرجاع، يكون التأثير هو تنفيذ

return 0;

يقول معيار C++ بوضوح "يجب أن تحتوي [الوظيفة الرئيسية] على نوع إرجاع من النوع int, ، ولكن بخلاف ذلك فإن نوعه هو التنفيذ المحدد"، ويتطلب نفس التوقيعين مثل معيار C ليتم دعمه كخيارات.لذا فإن "void main()" غير مسموح به بشكل مباشر بواسطة معيار C++، على الرغم من أنه لا يوجد شيء يمكن القيام به لإيقاف التنفيذ غير القياسي الذي يسمح بالبدائل.لاحظ أن C++ يمنع المستخدم من الاتصال main (لكن معيار C لا يفعل ذلك).

هناك فقرة من §18.5 البدء والانتهاء في معيار C++ 11 المطابق للفقرة من §7.22.4.4 ال exit وظيفة في معيار C11 (المذكور أعلاه)، بصرف النظر عن الحاشية السفلية (التي توثق ذلك ببساطة EXIT_SUCCESS و EXIT_FAILURE يتم تعريفها في <cstdlib>).

المعيار ج - الامتداد المشترك

بشكل كلاسيكي، تدعم أنظمة يونكس متغيرًا ثالثًا:

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

الوسيطة الثالثة عبارة عن قائمة منتهية بقيمة خالية من المؤشرات إلى السلاسل، كل منها عبارة عن متغير بيئة له اسم، وعلامة يساوي، وقيمة (ربما فارغة).إذا لم تستخدم هذا، فلا يزال بإمكانك الوصول إلى البيئة عبر 'extern char **environ;'.لفترة طويلة، لم يكن هناك رأس يعلن عنه، ولكن بوسيكس يتطلب معيار 2008 الآن الإعلان عنه <unistd.h>.

يتم التعرف على هذا بواسطة معيار C باعتباره امتدادًا شائعًا، موثقًا في الملحق J:

J.5.1 حجج البيئة

¶1 في بيئة مستضافة، تتلقى الوظيفة الرئيسية وسيطة ثالثة، char *envp[]، مما يشير إلى مجموعة من المؤشرات غير المنتهية char, ، كل منها يشير إلى سلسلة التي توفر معلومات حول البيئة لتنفيذ هذا البرنامج (5.1.2.2.1).

مايكروسوفت سي

ال مايكروسوفت مقابل 2010 المترجم مثير للاهتمام.يقول موقع الويب:

بناء جملة الإعلان عن الرئيسي هو

 int main();

أو، اختياريا،

int main(int argc, char *argv[], char *envp[]);

وبدلاً من ذلك، فإن main و wmain يمكن إعلان الوظائف على أنها عائدة void (لا توجد قيمة إرجاع).إذا أعلنت main أو wmain نظرًا لأن الإرجاع فارغ، فلا يمكنك إرجاع رمز الخروج إلى العملية الأصلية أو نظام التشغيل باستخدام عبارة الإرجاع.لإرجاع رمز الخروج متى main أو wmain تم الإعلان عنه void, ، يجب عليك استخدام exit وظيفة.

ليس من الواضح بالنسبة لي ما يحدث (ما هو رمز الخروج الذي يتم إرجاعه إلى الوالد أو نظام التشغيل) عندما يكون البرنامج به void main() يتم الخروج - وموقع ويب MS صامت أيضًا.

ومن المثير للاهتمام أن مرض التصلب العصبي المتعدد لا يصف إصدار الوسيطتين main() التي تتطلبها معايير C وC++.إنه يصف فقط نموذجًا من ثلاث وسيطات حيث تكون الوسيطة الثالثة char **envp, ، مؤشر إلى قائمة متغيرات البيئة.

تسرد صفحة Microsoft أيضًا بعض البدائل الأخرى — wmain() الذي يأخذ سلاسل أحرف واسعة، وبعضها أكثر.

مايكروسوفت فيجوال ستوديو 2005 نسخة من هذه الصفحة لا قائمة void main() كبديل.ال الإصدارات من مايكروسوفت فيجوال ستوديو 2008 فصاعدا القيام به.

المعيار C — البيئة القائمة بذاتها

كما ذكرنا سابقًا، تنطبق المتطلبات المذكورة أعلاه على البيئات المستضافة.إذا كنت تعمل مع بيئة قائمة بذاتها (وهي بديل للبيئة المستضافة)، فإن المعيار ليس لديه الكثير ليقوله.بالنسبة لبيئة قائمة بذاتها، لا يلزم استدعاء الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج main ولا توجد قيود على نوع الإرجاع الخاص به.المعيار يقول:

5.1.2 بيئات التنفيذ

تم تحديد بيئتين للتنفيذ:قائمة بذاتها واستضافتها.في كلتا الحالتين، يحدث بدء تشغيل البرنامج عندما يتم استدعاء وظيفة ج المعينة من قبل بيئة التنفيذ.يجب تهيئة جميع الكائنات ذات مدة التخزين الثابتة (ضبطها على قيمها الأولية) قبل بدء تشغيل البرنامج.طريقة وتوقيت هذه التهيئة غير محددين.يؤدي إنهاء البرنامج إلى إرجاع التحكم إلى بيئة التنفيذ.

5.1.2.1 بيئة قائمة بذاتها

في بيئة قائمة بذاتها (حيث قد يتم تنفيذ برنامج C دون أي فائدة من نظام التشغيل)، يتم تحديد اسم ونوع الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج من خلال التنفيذ.أي مرافق مكتبة متاحة لبرنامج قائم بذاته، بخلاف الحد الأدنى المطلوب بموجب البند 4، يتم تحديدها من خلال التنفيذ.

يتم تحديد تأثير إنهاء البرنامج في بيئة قائمة بذاتها من خلال التنفيذ.

تشير الإشارة المرجعية إلى البند 4 "المطابقة" إلى ما يلي:

¶5 أ برنامج مطابق تمامًا يجب أن تستخدم فقط ميزات اللغة والمكتبة المحددة في هذه المواصفة القياسية الدولية.3) ولا يجوز أن ينتج مخرجات تعتمد على أي سلوك غير محدد أو غير محدد أو محدد بالتنفيذ، ويجب ألا يتجاوز أي حد أدنى للتنفيذ.

¶6 الشكلان للتنفيذ المطابق هما مستضاف و قائما بذاتهمطابقة التنفيذ المستضاف يجب أن يقبل أي برنامج مطابق تمامًا.أ مطابقة التنفيذ القائم بذاته يجب أن يقبل أي برنامج مطابق تمامًا يقتصر فيه استخدام الميزات المحددة في بند المكتبة (البند 7) على محتويات الرؤوس القياسية <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, ، و <stdnoreturn.h>.قد يكون للتنفيذ المطابق امتدادات (بما في ذلك وظائف المكتبة الإضافية)، شريطة ألا تغير سلوك أي برنامج مطابق تمامًا.4)

¶7 أ برنامج المطابقة هو أمر مقبول للتنفيذ المطابق.5)

3) يمكن لبرنامج مطابق تمامًا استخدام الميزات الشرطية (انظر 6.10.8.3) بشرط أن يكون الاستخدام محميًا بتوجيه مناسب للمعالجة المسبقة للتضمين الشرطي باستخدام الماكرو ذي الصلة.على سبيل المثال:

#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */
    /* ... */
    fesetround(FE_UPWARD);
    /* ... */
#endif

4) وهذا يعني أن التنفيذ المطابق لا يحتفظ بمعرفات أخرى غير تلك المحفوظة صراحة في هذه المواصفة القياسية الدولية.

5) تهدف البرامج المطابقة تمامًا إلى أن تكون محمولة إلى الحد الأقصى بين التطبيقات المطابقة.قد تعتمد البرامج المطابقة على ميزات غير محمولة للتنفيذ المطابق.

من الملاحظ أن الرأس الوحيد المطلوب لبيئة قائمة بذاتها والتي تحدد فعليًا أي وظائف هو <stdarg.h> (وحتى تلك قد تكون - وغالبًا ما تكون - مجرد وحدات ماكرو).

معيار C++ — بيئة قائمة بذاتها

مثلما يتعرف معيار C على البيئة المستضافة والمستقلة، كذلك يفعل معيار C++.(مقتطفات من ISO/IEC 14882:2011.)

1.4 الامتثال للتنفيذ [intro.compliance]

¶7 تم تحديد نوعين من التطبيقات:أ التنفيذ المستضاف و أ التنفيذ القائم بذاته.بالنسبة للتنفيذ المستضاف، تحدد هذه المواصفة القياسية الدولية مجموعة المكتبات المتاحة.التنفيذ المستقل هو التنفيذ الذي قد يتم فيه التنفيذ دون الاستفادة من نظام التشغيل، ويحتوي على مجموعة محددة من المكتبات التي تتضمن مكتبات دعم لغوي معينة (17.6.1.3).

¶8 قد يشتمل التنفيذ المطابق على امتدادات (بما في ذلك وظائف مكتبة إضافية)، بشرط ألا تغير سلوك أي برنامج جيد التكوين.التطبيقات مطلوبة لتشخيص البرامج التي استخدام مثل هذه التمديدات غير المشكّلة وفقًا لهذه المواصفة القياسية الدولية.ومع ذلك، بعد القيام بذلك، يمكنهم تجميع وتنفيذ مثل هذه البرامج.

¶9 يجب أن يتضمن كل تطبيق وثائق تحدد جميع البنيات المدعومة بشكل مشروط والتي لا يدعمها ويحدد جميع الخصائص الخاصة بالإعدادات المحلية.3

3) تحدد هذه الوثائق أيضًا السلوك المحدد بالتنفيذ؛انظر 1.9.

17.6.1.3 التطبيقات القائمة بذاتها [الامتثال]

يتم تعريف نوعين من التطبيقات:مستضافة وقائما بذاته (1.4).بالنسبة للتنفيذ المستضاف، تصف هذه المواصفة القياسية الدولية مجموعة الرؤوس المتاحة.

يحتوي التنفيذ القائم بذاته على مجموعة من الرؤوس المحددة للتنفيذ.يجب أن تتضمن هذه المجموعة على الأقل الرؤوس المبينة في الجدول 16.

النسخة المقدمة من الرأس <cstdlib> يجب أن تعلن على الأقل المهام abort, atexit, at_quick_exit, exit, ، و quick_exit (18.5).يجب أن تستوفي الرؤوس الأخرى المدرجة في هذا الجدول نفس متطلبات التنفيذ المستضاف.

الجدول 16 - رؤوس C++ للتطبيقات القائمة بذاتها

Subclause                           Header(s)
                                    <ciso646>
18.2  Types                         <cstddef>
18.3  Implementation properties     <cfloat> <limits> <climits>
18.4  Integer types                 <cstdint>
18.5  Start and termination         <cstdlib>
18.6  Dynamic memory management     <new>
18.7  Type identification           <typeinfo>
18.8  Exception handling            <exception>
18.9  Initializer lists             <initializer_list>
18.10 Other runtime support         <cstdalign> <cstdarg> <cstdbool>
20.9  Type traits                   <type_traits>
29    Atomics                       <atomic>

ماذا عن استخدام int main() شركة؟

يُظهر المعيار §5.1.2.2.1 من معيار C11 التدوين المفضل -int main(void) - ولكن هناك أيضًا مثالين في المعيار يظهران int main(): §6.5.3.4 ¶8 و §6.7.6.3 ¶20.الآن، من المهم أن نلاحظ أن الأمثلة ليست "معيارية"؛فهي توضيحية فقط.إذا كانت هناك أخطاء في الأمثلة، فإنها لا تؤثر بشكل مباشر على النص الرئيسي للمعيار.ومع ذلك، فهي تشير بقوة إلى السلوك المتوقع، لذلك إذا كان المعيار يتضمن int main() في مثال، يقترح ذلك int main() ولا يحرم، وإن لم يكن هو التدوين المفضل.

6.5.3.4 sizeof و _Alignof العاملين

¶8 مثال 3 في هذا المثال، يتم حساب حجم مصفوفة متغيرة الطول وإرجاعها من دالة:

#include <stddef.h>

size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}
int main()
{
    size_t size;
    size = fsize3(10); // fsize3 returns 13
    return 0;
}

أعتقد أن main() يجب أن يعود سواء EXIT_SUCCESS أو EXIT_FAILURE.يتم تعريفهم في stdlib.h

لاحظ أن معايير C وC++ تحدد نوعين من التطبيقات:قائمة بذاتها واستضافتها.

  • البيئة المستضافة C90

    النماذج المسموح بها 1:

    int main (void)
    int main (int argc, char *argv[])
    
    main (void)
    main (int argc, char *argv[])
    /*... etc, similar forms with implicit int */
    

    تعليقات:

    تم ذكر النموذجين السابقين بشكل صريح على أنهما النماذج المسموح بها، بينما تم السماح بالنماذج الأخرى ضمنيًا لأن C90 سمح بـ "int ضمني" لنوع الإرجاع ومعلمات الوظيفة.ولا يسمح بأي شكل آخر.

  • بيئة قائمة بذاتها C90

    يُسمح بأي شكل أو اسم رئيسي 2.

  • البيئة المستضافة C99

    النماذج المسموح بها 3:

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
    

    تعليقات:

    قام C99 بإزالة "الكثافة الضمنية" لذلك main() لم يعد صالحا.

    تم تقديم جملة غريبة وغامضة "أو بطريقة أخرى محددة للتنفيذ".يمكن تفسير ذلك على أنه "المعلمات". int main() قد تختلف" أو "يمكن أن يكون للمفتاح الرئيسي أي نموذج محدد للتنفيذ".

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

    ومع ذلك، للسماح بالأشكال البرية تمامًا main() ربما (؟) لم يكن القصد من هذه الجملة الجديدة.يشير الأساس المنطقي C99 (وليس المعياري) إلى أن الجملة تشير إلى معلمات إضافية لـ int main 4.

    ومع ذلك، يستمر القسم الخاص بإنهاء برنامج البيئة المستضافة في الجدال حول الحالة التي لا يُرجع فيها main عدد int 5.على الرغم من أن هذا القسم ليس معياريًا لكيفية الإعلان عن main، إلا أنه يشير بالتأكيد إلى أنه قد يتم الإعلان عن main بطريقة محددة التنفيذ تمامًا حتى على الأنظمة المستضافة.

  • بيئة قائمة بذاتها C99

    يُسمح بأي شكل أو اسم رئيسي 6.

  • البيئة المستضافة لـ C11

    النماذج المسموح بها 7:

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
    
  • بيئة قائمة بذاتها C11

    يُسمح بأي شكل أو اسم رئيسي 8.


لاحظ أن int main() لم يتم إدراجه أبدًا كنموذج صالح لأي تطبيق مستضاف لـ C في أي من الإصدارات المذكورة أعلاه.في لغة C، على عكس C++، () و (void) لها معاني مختلفة.فالأولى هي سمة متقادمة يمكن إزالتها من اللغة.راجع اتجاهات اللغة المستقبلية لـ C11:

6.11.6 معلنات الوظائف

يعد استخدام معلنات الوظائف ذات الأقواس الفارغة (وليس معلنات نوع معلمة تنسيق النموذج الأولي) ميزة قديمة.


  • البيئة المستضافة لـ C++03

    النماذج المسموح بها 9:

    int main ()
    int main (int argc, char *argv[])
    

    تعليقات:

    لاحظ القوس الفارغ في النموذج الأول.يختلف C++ وC في هذه الحالة، لأن هذا يعني في C++ أن الدالة لا تأخذ أي معلمات.ولكن في لغة C فهذا يعني أنه قد يستغرق أي معلمة.

  • بيئة قائمة بذاتها C++03

    اسم الوظيفة التي يتم استدعاؤها عند بدء التشغيل محدد بالتنفيذ.إذا تم تسميته main() ويجب أن تتبع النماذج المذكورة 10:

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
    
  • البيئة المستضافة لـ C++ 11

    النماذج المسموح بها 11:

    int main ()
    int main (int argc, char *argv[])
    

    تعليقات:

    تم تغيير نص المعيار ولكن له نفس المعنى.

  • بيئة قائمة بذاتها لـ C++11

    اسم الوظيفة التي يتم استدعاؤها عند بدء التشغيل محدد بالتنفيذ.إذا تم تسميته main() ويجب أن تتبع النماذج المذكورة 12:

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
    

مراجع

  1. ANSI X3.159-1989 2.1.2.2 البيئة المستضافة."بدء تشغيل البرنامج"

    تسمى الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج بالرئيسية.يعلن التنفيذ عدم وجود نموذج أولي لهذه الوظيفة.يجبتعريفه بنوع عائد من الفائدة وبدون معلمات:

    int main(void) { /* ... */ } 
    

    أو بمعلمتين (يشار إليهما هنا باسم حجج و حجج، على الرغم من أنه يمكن استخدام أي أسماء، لأنها محلية الوظيفة التي يتم الإعلان عنها فيها):

    int main(int argc, char *argv[]) { /* ... */ }
    
  2. ANSI X3.159-1989 2.1.2.1 بيئة قائمة بذاتها:

    في بيئة قائمة بذاتها (حيث قد يستغرق تنفيذ البرنامج ج المكان دون أي فائدة من نظام التشغيل)، الاسم والنوع من الوظيفة المسماة عند بدء تشغيل البرنامج يتم تعريفها بالتنفيذ.

  3. ISO 9899:1999 5.1.2.2 البيئة المستضافة -> 5.1.2.2.1 بدء تشغيل البرنامج

    تسمى الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج بالرئيسية.يعلن التنفيذ عدم وجود نموذج أولي لهذه الوظيفة.يجبتعريفه بنوع عائد من الفائدة وبدون معلمات:

    int main(void) { /* ... */ } 
    

    أو بمعلمتين (يشار إليهما هنا باسم حجج و حجج، على الرغم من أنه يمكن استخدام أي أسماء، لأنها محلية الوظيفة التي يتم الإعلان عنها فيها):

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

    أو ما يعادلها ؛9) أو بطريقة أخرى محددة للتنفيذ.

  4. الأساس المنطقي للمعايير الدولية – لغات البرمجة – C، المراجعة 5.10.5.1.2.2 البيئة المستضافة --> 5.1.2.2.1 بدء تشغيل البرنامج

    سلوك الحجج الرئيسية، وتفاعل الخروج، الرئيسي والخروج (انظر القسم 7.20.4.2) للحد من بعض التنوع غير المرغوب فيه في تمثيل الحجج السلاسل، وبمعنى القيم التي أعادتها الرئيسية.

    إن مواصفات argc و argv كوسائط للمفتاح الرئيسي تعترف بممارسات سابقة واسعة النطاق.يجب أن يكون argv[argc] مؤشرًا فارغًا لتوفير فحص زائد لنهاية القائمة، وذلك أيضًا على أساس الممارسة الشائعة.

    main هي الوظيفة الوحيدة التي يمكن الإعلان عنها بشكل محمول إما باستخدام وسيطة صفر أو وسيطتين.(يجب أن يتطابق عدد حجج الوظائف الأخرى تمامًا بين الاستدعاء والتعريف.) تعترف هذه الحالة الخاصة ببساطة بالممارسة الواسعة الانتشار المتمثلة في ترك الحجج الرئيسية عندما لا يصل البرنامج إلى سلاسل حجج البرنامج.في حين أن العديد من التطبيقات تدعم أكثر من حجتين للمفتاح الرئيسي، فإن مثل هذه الممارسة ليست مباركة ولا محظورة بواسطة المعيار؛البرنامج الذي يحدد main بثلاث وسيطات لا يتوافق بشكل صارم (انظر الفقرة 1.5.J).

  5. ISO 9899:1999 5.1.2.2 البيئة المستضافة --> 5.1.2.2.3 إنهاء البرنامج

    إذا كان نوع الإرجاع للوظيفة الرئيسية هو نوع متوافق مع int، فإن العودة من الاستدعاء الأولي إلى الوظيفة الرئيسية تعادل استدعاء وظيفة الخروج مع القيمة التي أرجعتها الوظيفة الرئيسية كوسيطة لها؛11) الوصول إلى } الذي ينهي الوظيفة الرئيسية يُرجع قيمة 0.إذا كان نوع الإرجاع غير متوافق مع int، فإن حالة الإنهاء التي تم إرجاعها إلى البيئة المضيفة تكون غير محددة.

  6. ISO 9899:1999 5.1.2.1 بيئة قائمة بذاتها

    في بيئة قائمة بذاتها (حيث قد يتم تنفيذ برنامج C دون أي فائدة من نظام التشغيل)، يتم تحديد اسم ونوع الوظيفة التي يتم استدعاؤها عند بدء تشغيل البرنامج من خلال التنفيذ.

  7. ISO 9899:2011 5.1.2.2 البيئة المستضافة -> 5.1.2.2.1 بدء تشغيل البرنامج

    هذا القسم مطابق للقسم C99 المذكور أعلاه.

  8. ISO 9899:1999 5.1.2.1 بيئة قائمة بذاتها

    هذا القسم مطابق للقسم C99 المذكور أعلاه.

  9. ISO 14882:2003 3.6.1 الوظيفة الرئيسية

    يجب ألا يحدد التنفيذ الوظيفة الرئيسية مسبقًا.لا يجوز تحميل هذه الوظيفة بشكل زائد.يجب أن يكون له نوع إرجاع من النوع int، وإلا فإن نوعه محدد بالتنفيذ.يجب أن تسمح جميع التطبيقات بالتعريفين الرئيسيين التاليين:

    int main() { /* ... */ }
    

    و

    int main(int argc, char* argv[]) { /* ... */ }
    
  10. ISO 14882:2003 3.6.1 الوظيفة الرئيسية

    يتم تحديد التنفيذ فيما إذا كان البرنامج في بيئة قائمة بذاتها مطلوبًا لتحديد وظيفة رئيسية.

  11. ISO 14882:2011 3.6.1 الوظيفة الرئيسية

    يجب ألا يحدد التنفيذ الوظيفة الرئيسية مسبقًا.لا يجوز تحميل هذه الوظيفة بشكل زائد.يجب أن يكون له نوع إرجاع من النوع int، وإلا فإن نوعه محدد بالتنفيذ.يجب أن تسمح جميع عمليات التنفيذ بكليهما

    - دالة () ترجع int و

    - دالة (int، مؤشر إلى مؤشر إلى char) تُرجع int

    كنوع رئيسي (8.3.5).

  12. ISO 14882:2011 3.6.1 الوظيفة الرئيسية

    هذا القسم مطابق للقسم C++03 المذكور أعلاه.

قم بإرجاع 0 عند النجاح وغير صفر للخطأ.هذا هو المعيار الذي تستخدمه البرمجة النصية لنظامي UNIX وDOS لمعرفة ما حدث لبرنامجك.

main() في C89 وK&R C، تكون أنواع الإرجاع غير المحددة هي القيمة الافتراضية "int".

return 1? return 0?
  1. إذا لم تكتب بيان الإرجاع في int main(), ، الختام { سيعود 0 افتراضيا.

  2. return 0 أو return 1 سيتم استلامها من خلال العملية الأم.في الصدفة يتم الانتقال إلى متغير الصدفة، وإذا كنت تقوم بتشغيل البرنامج الخاص بك من الصدفة ولا تستخدم هذا المتغير، فلا داعي للقلق بشأن القيمة المرجعة لـ main().

يرى كيف يمكنني الحصول على ما أعادته وظيفتي الرئيسية؟.

$ ./a.out
$ echo $?

بهذه الطريقة يمكنك أن ترى أنه المتغير $? الذي يتلقى البايت الأقل أهمية من القيمة المرجعة لـ main().

في البرمجة النصية Unix وDOS، return 0 عند النجاح وغير الصفر للخطأ عادة ما يتم إرجاعها.هذا هو المعيار الذي تستخدمه البرمجة النصية لنظامي Unix وDOS لمعرفة ما حدث لبرنامجك والتحكم في التدفق بالكامل.

ضع في اعتبارك أنه على الرغم من أنك تقوم بإرجاع int، فإن بعض أنظمة التشغيل (Windows) تقوم باقتطاع القيمة التي يتم إرجاعها إلى بايت واحد (0-255).

يمكن لنظام التشغيل استخدام قيمة الإرجاع للتحقق من كيفية إغلاق البرنامج.

عادةً ما تعني القيمة المرجعة 0 موافق في معظم أنظمة التشغيل (تلك التي يمكنني التفكير فيها على أي حال).

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

إنه لا مجرد اتفاقية البرمجة.

قيمة الإرجاع main() يبين كيف خرج البرنامج.إذا كانت قيمة الإرجاع هي zero فهذا يعني أن التنفيذ كان ناجحًا في حين أن أي قيمة غير الصفر ستشير إلى حدوث خطأ ما أثناء التنفيذ.

كان لدي انطباع بأن المعيار يحدد أن main لا يحتاج إلى قيمة إرجاع لأن الإرجاع الناجح كان يعتمد على نظام التشغيل (الصفر في أحدهما يمكن أن يكون نجاحًا أو فشلًا في الآخر)، وبالتالي فإن غياب الإرجاع كان بمثابة إشارة إلى مترجم لإدراج العودة الناجحة نفسها.

ومع ذلك أعود عادة 0.

عودة 0 يجب أن تخبر المبرمج أن البرنامج قد أنهى المهمة بنجاح.

حذف return 0

عندما يصل برنامج C أو C++ إلى نهاية main سيقوم المترجم تلقائيًا بإنشاء رمز لإرجاع 0، لذلك ليست هناك حاجة لوضعه return 0; صراحة في نهاية main.

ملحوظة: عندما أقدم هذا الاقتراح، فإنه دائمًا ما يتبعه أحد نوعين من التعليقات:"لم أكن أعرف ذلك." أو "هذه نصيحة سيئة!" الأساس المنطقي هو أنه من الآمن والمفيد الاعتماد على سلوك المترجم المدعوم بشكل صريح من المعيار.بالنسبة لـ C، منذ C99؛راجع ISO/IEC 9899:1999 القسم 5.1.2.2.3:

[...] عودة من المكالمة الأولية إلى main الدالة تعادل استدعاء exit الدالة بالقيمة التي تم إرجاعها بواسطة الدالة main تعمل كحجة لها؛الوصول إلى } الذي ينهي main ترجع الدالة قيمة 0.

بالنسبة لـ C++، منذ المعيار الأول في عام 1998؛راجع ISO/IEC 14882:1998 القسم 3.6.1:

إذا وصل التحكم إلى نهاية main دون مواجهة بيان الإرجاع، فسيكون التأثير هو تنفيذ الإرجاع 0؛

حافظت جميع إصدارات كلا المعيارين منذ ذلك الحين (C99 وC++98) على نفس الفكرة.نحن نعتمد على وظائف الأعضاء التي يتم إنشاؤها تلقائيًا في لغة C++، وقليل من الأشخاص يكتبون بشكل صريح return; البيانات في نهاية أ void وظيفة.يبدو أن الأسباب ضد الحذف تتلخص في "يبدو غريب".إذا كنت مثلي مهتمًا بمعرفة الأساس المنطقي للتغيير إلى معيار C اقرأ هذا السؤال.لاحظ أيضًا أنه في أوائل التسعينيات كان هذا يعتبر "ممارسة قذرة" لأنه كان سلوكًا غير محدد (على الرغم من دعمه على نطاق واسع) في ذلك الوقت.

بالإضافة إلى ذلك، المبادئ التوجيهية الأساسية لـ C++ يحتوي على حالات متعددة من الحذف return 0; في نهاية main ولا توجد حالات يتم فيها كتابة إرجاع صريح.وعلى الرغم من عدم وجود مبادئ توجيهية محددة بشأن هذا الموضوع بالتحديد في تلك الوثيقة، إلا أن ذلك يبدو على الأقل بمثابة موافقة ضمنية على هذه الممارسة.

لذا فإنني أدعو إلى حذفها؛يختلف الآخرون (بشدة في كثير من الأحيان!) على أية حال، إذا واجهت رمزًا يحذفه، فستعرف أنه مدعوم بشكل صريح بواسطة المعيار وستعرف ما يعنيه.

ما يجب إرجاعه يعتمد على ما تريد القيام به مع الملف القابل للتنفيذ.على سبيل المثال، إذا كنت تستخدم برنامجك مع غلاف سطر الأوامر، فأنت بحاجة إلى إرجاع 0 للنجاح وغير صفر للفشل.ستتمكن بعد ذلك من استخدام البرنامج في الأصداف مع المعالجة المشروطة اعتمادًا على نتيجة التعليمات البرمجية الخاصة بك.يمكنك أيضًا تعيين أي قيمة غير صفرية وفقًا لتفسيرك، على سبيل المثال بالنسبة للأخطاء الفادحة، يمكن لنقاط خروج مختلفة للبرنامج إنهاء برنامج بقيم خروج مختلفة، وهي متاحة لصدفة الاستدعاء التي يمكنها أن تقرر ما يجب فعله عن طريق فحص القيمة التي تم إرجاعها.إذا لم يكن الكود مخصصًا للاستخدام مع الأصداف وكانت القيمة التي تم إرجاعها لا تزعج أي شخص، فقد يتم حذفها.أنا شخصياً أستخدم التوقيع int main (void) { .. return 0; .. }

إذا كانت لديك بالفعل مشكلات تتعلق بكفاءة إرجاع عدد صحيح من عملية ما، فمن المحتمل أن تتجنب استدعاء هذه العملية عدة مرات حتى تصبح قيمة الإرجاع هذه مشكلة.

إذا كنت تفعل هذا (استدعاء عملية عدة مرات)، فيجب أن تجد طريقة لوضع المنطق الخاص بك مباشرةً داخل المتصل، أو في ملف DLL، دون تخصيص عملية محددة لكل استدعاء؛تجلب لك تخصيصات العمليات المتعددة مشكلة الكفاءة ذات الصلة في هذه الحالة.

بالتفصيل، إذا كنت تريد فقط معرفة ما إذا كان إرجاع 0 أكثر أو أقل كفاءة من إرجاع 1، فقد يعتمد ذلك على المترجم في بعض الحالات، ولكن بشكل عام، على افتراض أنه تمت قراءتها من نفس المصدر (محلي، ميداني، ثابت، مضمن) في الكود، ونتيجة الوظيفة، وما إلى ذلك) يتطلب نفس عدد دورات الساعة بالضبط.

ما هي الطريقة الصحيحة (الأكثر فعالية) لتحديد الدالة main() في C وC++ — int main() أو void main() — ولماذا؟

هذه الكلمات "(الأكثر كفاءة)" لا تغير السؤال.ما لم تكن في بيئة قائمة بذاتها، هناك طريقة واحدة صحيحة عالميًا للإعلان main(), ، وهذا بمثابة إرجاع int.

ماذا يجب main() العودة في C وC++؟

ليس هذا ما يجب main() العودة، وهذا ما يفعل main() يعود. main() هي بالطبع وظيفة يستدعيها شخص آخر.ليس لديك أي سيطرة على الرمز الذي يتصل main().لذلك عليك أن تعلن main() مع نوع التوقيع الصحيح لمطابقة المتصل به.ببساطة ليس لديك أي خيار في هذا الشأن.ليس عليك أن تسأل نفسك ما هو أكثر أو أقل كفاءة، أو ما هو الأسلوب الأفضل أو الأسوأ، أو أي شيء من هذا القبيل، لأن الإجابة محددة جيدًا بالفعل، بالنسبة لك، وفقًا لمعايير C وC+.فقط اتبعهم.

إذا int main() ثم قم بإرجاع 1 أو إرجاع 0؟

0 للنجاح، غير صفر للفشل.مرة أخرى، ليس شيئًا تحتاج إلى اختياره (أو الوصول إليه):يتم تعريفه من خلال الواجهة التي من المفترض أن تتوافق معها.

فيما يلي عرض توضيحي صغير لاستخدام رموز الإرجاع...

عند استخدام الأدوات المتنوعة التي توفرها محطة Linux، يمكن للمرء استخدام رمز الإرجاع، على سبيل المثال، لمعالجة الأخطاء بعد اكتمال العملية.تخيل أن الملف النصي التالي myfile موجود:

هذا بعض الأمثلة للتحقق من كيفية عمل grep.

عند تنفيذ الأمر grep يتم إنشاء عملية.بمجرد الانتهاء (ولم ينقطع) فإنه يُرجع بعض التعليمات البرمجية بين 0 و255.على سبيل المثال:

$ grep order myfile

اذا فعلت

$ echo $?
$ 0

سوف تحصل على 0.لماذا؟لأن grep عثر على تطابق وأعاد رمز الخروج 0، وهو القيمة المعتادة للخروج بنجاح.دعونا نتحقق من ذلك مرة أخرى ولكن باستخدام شيء غير موجود داخل ملفنا النصي وبالتالي لن يتم العثور على أي تطابق:

$ grep foo myfile
$ echo $?
$ 1

نظرًا لأن grep فشل في مطابقة الرمز المميز "foo" مع محتوى ملفنا، فإن رمز الإرجاع هو 1 (هذه هي الحالة المعتادة عند حدوث فشل ولكن كما هو مذكور أعلاه، لديك الكثير من القيم للاختيار من بينها).

الآن، نص bash التالي (ما عليك سوى كتابته في محطة Linux) على الرغم من كونه أساسيًا جدًا، إلا أنه يجب أن يعطي فكرة عن معالجة الأخطاء:

$ grep foo myfile
$ CHECK=$?
$ [ $CHECK -eq 0] && echo 'Match found'
$ [ $CHECK -ne 0] && echo 'No match was found'
$ No match was found

بعد السطر الثاني، لا تتم طباعة أي شيء على الجهاز لأن "foo" قام بإرجاع grep إلى 1 ونتحقق مما إذا كان رمز الإرجاع لـ grep يساوي 0.العبارة الشرطية الثانية تردد رسالتها في السطر الأخير لأنها صحيحة بسبب CHECK == 1.

كما ترون، إذا كنت تتصل بهذه العملية وتلك، فمن الضروري أحيانًا معرفة ما تم إرجاعه (من خلال القيمة المرجعة لـ main()).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top