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

جملة switch في ++C: الحالات والانسياب وbreak

شرح جملة switch في ++C: تسميات case، وbreak والانسياب (fall-through)، وفرع default، وتجميع الحالات، وswitch على enum، والمزالق المتعلقة بالتصريحات داخل الحالات.

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

ما الغرض من switch

تقارن جملة switch قيمة واحدة بقائمة من الخيارات الثابتة وتنفّذ الفرع المطابق. وعندما تجد نفسك تكتب سلسلة طويلة من if/else if تختبر المتغير نفسه مرارًا مقابل ثوابت مختلفة، فإن switch يعبّر عن هذا القصد بوضوح أكبر، وغالبًا ما يُترجم إلى جدول قفز أسرع.

وهو لا يجري سوى فحوص المساواة مقابل ثوابت تُعرف وقت الترجمة على قيمة شبيهة بعدد صحيح. ولا يستطيع اختبار المجالات، أو مقارنة السلاسل النصية، أو دمج الشروط. ولأيٍّ من ذلك، ابقَ مع if/else.

switch الأساسي

تعطي switch قيمةً، ثم تعدّد تسميات case للقيم التي تهمّك. وينتهي كل فرع بـ break:

تتطابق القيمة 3 مع case 3:، فتُطبع "Wednesday" ويقفز break خارج الـ switch. وفرع default هو الفرع الجامع؛ يُنفَّذ حين لا تتطابق أي حالة case. وهو اختياري، لكن ضمّنه ما لم تكن متأكدًا أن كل قيمة مُعالَجة.

لاحظ أن تسميات case ثوابت مجردة يتبعها نقطتان رأسيتان، لا شروط. فتكتب case 3:، ولا تكتب أبدًا case day == 3:.

break والانسياب

هذا أهم مزلق في switch في ++C. بعد أن تتطابق إحدى الحالات، لا يتوقف التنفيذ عند الحالة التالية، بل يستمر مباشرةً حتى يصل إلى break أو إلى القوس المعقوف الختامي. انظر ما يحدث حين تغيب جُمل break:

قد تتوقع طباعة "one" فقط، لكن تُطبع الأسطر الأربعة جميعها؛ إذ يؤدي التطابق مع case 1: إلى الدخول في الـ switch هناك ثم الانسياب عبر كل التسميات أسفله. أضِف break; بعد كل فرع تحصل على السطر الوحيد الذي أردته. ونسيان break هو المصدر الكلاسيكي لأخطاء «لماذا ينفّذ الـ switch لديّ شيفرة أكثر من اللازم؟».

انسياب مقصود لتجميع الحالات

ليس الانسياب خطأً دائمًا؛ بل هو الأسلوب المتعارف عليه لجعل عدة حالات تتشارك جسمًا واحدًا. اترك الحالات فارغة (بلا جُمل ولا break) فتنساب جميعها إلى الكتلة التالية:

تصل 'A' و'B' و'C' جميعها إلى سطر "Pass" نفسه، لأن أول حالتين فارغتان وتنسابان إلى الثالثة. وهذا نظيف ومقصود. أما حين تقصد فعلًا الانسياب بعد تنفيذ بعض الشيفرة، فوثّق ذلك بتعليق، أو في ++C17 وما بعده استخدم السمة [[fallthrough]];، التي تخبر المترجم «نعم، قصدت هذا» وتُسكِت تحذيرات الانسياب.

switch على enum

ينسجم switch بطبيعته مع enums، لأن الـ enum هو بالضبط «واحدة من مجموعة ثابتة من القيم». كما يمكن للمترجمات أن تحذرك إذا نسيت معالجة أحد عناصر التعداد:

مع enum class ذي النطاق، عليك تأهيل كل تسمية (Direction::East). ولأن كل عناصر التعداد مغطّاة، فلا حاجة إلى default، وكثير من المترجمات سيحذّرك إن أضفت لاحقًا اتجاهًا خامسًا ونسيت إضافة حالته. هذه المساعدة من المترجم سبب وجيه لتفضيل switch على سلاسل if/else مع التعدادات.

مزلق: التصريحات داخل حالة case

لا يمكنك التصريح عن متغير بقيمة ابتدائية داخل حالة وجعله مرئيًا عبر بقية الحالات دون حصره ضمن نطاق. وهذا خطأ ترجمة شائع:

switch (x) {
    case 1:
        int n = 10;   // خطأ: القفز إلى case 2 يتجاوز هذا التهيئة
        cout << n;
        break;
    case 2:
        cout << "two";
        break;
}

يرفض المترجم ذلك لأن الانسياب إلى case 2: سيقفز فوق تهيئة n بينما لا يزال n ضمن النطاق. والحل هو تغليف جسم الحالة بأقواس معقوفة خاصة به، فتمنح المتغير كتلة مستقلة:

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

التالي: حلقة for

تتيح switch وif لبرنامجك أن يختار أيّ شيفرة يُنفّذ مرةً واحدة. لكن كثيرًا من العمل يعني فعل الشيء نفسه مرات عديدة: العدّ، والمرور على قائمة، والتكرار حتى يتغير شرط ما. وحلقة for هي أداة العمل الأساسية لذلك، وهي الصفحة التالية.

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

متى ينبغي أن أستخدم switch بدلاً من if-else في ++C؟

استخدم switch عندما تقارن قيمة واحدة شبيهة بعدد صحيح مع عدد كبير من الخيارات الثابتة والمتمثلة في قيم ثابتة، مثل اختيار من قائمة، أو رقم يوم، أو enum. فهو أوضح في القراءة من سلسلة طويلة من if/else if، ويتيح للمترجم تحسين التوجيه. ابقَ مع if/else عندما تشمل شروطك مجالات (x > 10) أو قيمًا عشرية أو سلاسل نصية أو عدة متغيرات؛ فإن switch لا يستطيع فعل أيٍّ من ذلك.

لماذا أحتاج إلى break في جملة switch في ++C؟

بمجرد أن تتطابق إحدى الحالات case، يواصل ++C تنفيذ الحالات التالية حتى يصل إلى break أو إلى نهاية الـ switch. يُسمى هذا الانسياب (fall-through). وbreak هو ما يوقفه. ونسيان break خطأ كلاسيكي؛ إذ تتطابق مع case 1: ثم تنفّذ عن غير قصد شيفرة case 2 وcase 3 وdefault أيضًا.

ما الأنواع التي يمكن استخدام switch عليها في ++C؟

الأنواع الصحيحة أو التعدادية فقط: int وchar وshort وlong وbool، وenum بنطاق أو بدون نطاق، وأي شيء يتحول إلى أحدها. لا يمكنك استخدام switch على double أو float أو std::string؛ استعمل if/else لتلك الحالات. ويجب أن تكون كل تسمية case ثابتًا يُعرف وقت الترجمة.

Coddy programming languages illustration

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

ابدأ الآن