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

معاملات C++: الحسابية والمقارنة والمنطقية وغيرها

تعلّم معاملات C++ - الحسابية والمقارنة والمنطقية والإسناد والمعاملات على مستوى البتات - إضافة إلى المزالق المتعلقة بالقسمة الصحيحة والأسبقية والتقييم القصير.

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

ما الذي تفعله المعاملات

المعامل رمز يُجري عملية على قيمة واحدة أو أكثر تُسمى المعاملات. لقد استخدمت بالفعل واحدًا منها: علامة = التي تربط قيمة بمتغير. تأتي C++ بمجموعة غنية من المعاملات للرياضيات والمقارنة والمنطق ومعالجة البتات - مع بعض الزوايا الحادة التي تُعثِر المبتدئين.

في الصفحة السابقة رأيت كيف تُثبّت const قيمةً ما. أما المعاملات فهي الطريقة التي تحسب بها القيم التي تخزّنها، سواء كانت ثابتة أم لا. لنستعرض المجموعات التي ستستخدمها كل يوم.

المعاملات الحسابية

المعاملات الحسابية الخمسة هي + و - و * و / و % (باقي القسمة، أي ما يتبقى من عملية القسمة):

المزلق الكبير يكمن في ذلك الناتج. فـ 17 / 5 تطبع 3 لا 3.4. عندما يكون كلا المعاملَين عددًا صحيحًا، تُجري / قسمة صحيحة وتُلقي بالجزء الكسري - فهي تقتطع باتجاه الصفر، ولا تُقرّب. وإذا أردت كسرًا حقيقيًا، فيجب أن يكون أحد المعاملَين على الأقل قيمة عشرية:

المعامل % يعمل مع الأعداد الصحيحة فقط. واستخدام % على قيمة double خطأ في الترجمة - استخدم std::fmod من <cmath> للحصول على باقي قسمة الأعداد العشرية.

الإسناد والمعاملات المركّبة

علامة = المفردة تُسنِد؛ ولا تُقارن. تمنحك C++ صيغًا مركّبة تجمع بين عملية والإسناد كي لا تُكرّر اسم المتغير:

من الأخطاء الكلاسيكية المؤلمة كتابة = بينما تقصد == داخل شرط. فـ if (x = 0) تُسنِد القيمة 0 إلى x ثم تختبر الناتج (وهو قيمة خاطئة)، بدلًا من المقارنة. وتُنبّهك المترجمات الحديثة إلى ذلك عند تفعيل التحذيرات - أبقِ -Wall مفعّلًا وتعامل مع التحذير بجدية.

معاملات المقارنة

تطرح معاملات المقارنة سؤالًا بنعم/لا وتُنتج قيمة bool (true أو false):

افتراضيًا تطبع cout قيمة bool على هيئة 1 أو 0. أدخِل boolalpha مرة واحدة فتتحوّل إلى الكلمتين true/false لبقية ذلك المجرى.

وهناك فخّ دقيق: لا تربط المقارنات على هذا النحو 1 < x < 10. فهذا يُحلَّل على أنه (1 < x) < 10 - تُنتج المقارنة الأولى قيمة bool (0 أو 1)، ثم تُقارَن بـ 10، فيكون الناتج الكامل دائمًا تقريبًا true. اكتب بدلًا من ذلك 1 < x && x < 10.

المعاملات المنطقية والتقييم القصير

تجمع && (و)، و || (أو)، و ! (نفي) بين التعبيرات المنطقية. والمعاملان الأولان يستخدمان التقييم القصير: يتوقف التقييم بمجرد معرفة الناتج.

لا تُنفَّذ check("A") ولا check("B") أبدًا - هذا هو التقييم القصير. وهو ليس مجرد تحسين؛ بل أداة. إذ يمكنك أن تكتب بأمان if (ptr != nullptr && ptr->ready) لأن الجزء ptr->ready لا يُبلَغ إلا عندما يكون ptr غير فارغ (non-null)، مما يتجنّب الوصول إلى مؤشر معلّق.

الزيادة والإنقاص

++ تضيف واحدًا؛ و -- تطرح واحدًا. ولكلٍّ منهما صيغة سابقة وأخرى لاحقة، ويصبح الفرق مهمًا عند استخدام الناتج:

عندما تريد الأثر الجانبي فقط (في حلقة for مثلًا)، فضّل ++i. فمع النوع int البسيط هما متطابقان، لكن مع الأنواع الأثقل مثل المُكرِّرات (iterators) تضطر الزيادة اللاحقة إلى نسخ القيمة القديمة أولًا، وهذا جهد مُهدَر.

تحذير أخير: لا تُعدّل المتغير نفسه مرتين داخل تعبير واحد، مثل i = i++ + 1; أو arr[i] = i++;. فترتيب هذه التحديثات غير محدّد والنتيجة سلوك غير معرَّف. اجعل لكل متغير تعديلًا واحدًا فقط في كل جملة.

المعاملات على مستوى البتات والأسبقية

للعمل منخفض المستوى توجد معاملات على مستوى البتات: & (و)، و | (أو)، و ^ (xor)، و ~ (نفي)، إضافة إلى معاملَي الإزاحة << و >>.

انتبه: << و >> هما أيضًا معاملا المجرى على cout. فداخل سطر cout تحتاج عادةً إلى أقواس حول إزاحة البتات، وإلا قرأها المترجم على أنها إدراج في المجرى.

وأخيرًا، تُحدّد الأسبقية ما الذي يرتبط أولًا عند مزج المعاملات. فـ * و / ترتبطان بقوة أكبر من + و -، تمامًا كما في الرياضيات، لذا فإن 2 + 3 * 4 يساوي 14. وترتبط المقارنة بقوة أقل من العمليات الحسابية، والمعاملان المنطقيان &&/|| بقوة أقل من ذلك. وعند الشك، لا تحفظ الجدول كاملًا - أضِف أقواسًا. فالصيغة (a + b) * c أوضح من الاعتماد على تذكّر القارئ للقواعد.

التالي: تحويل الأنواع

رأيت أعلاه أن (double)a / b أجبرت عددًا صحيحًا على الدخول في قسمة عشرية. هذا هو التحويل (cast) - تحويل قيمة عمدًا من نوع إلى آخر. في الصفحة التالية سنتناول أدوات التحويل في C++، من الترقيات الضمنية إلى static_cast، ومتى يكون كلٌّ منها آمنًا.

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

ما هي المعاملات في C++؟

تُصنّف C++ المعاملات إلى حسابية (+ - * / %)، ومقارنة (== != < > <= >=)، ومنطقية (&& || !)، وإسناد (= += -= ...)، وزيادة/إنقاص (++ --)، ومعاملات على مستوى البتات (& | ^ ~ << >>). كما يوجد المعامل الثلاثي ?: وبعض المعاملات الأخرى مثل sizeof.

لماذا يساوي 5 / 2 القيمة 2 في C++؟

لأن كلا المعاملَين من النوع int، فإن / تُجري قسمة صحيحة ويُهمَل الجزء الكسري - دون تقريب. للحصول على 2.5، اجعل أحد المعاملَين على الأقل قيمة عشرية: 5.0 / 2 أو 5 / 2.0.

ما الفرق بين ++i و i++ في C++؟

كلاهما يضيف 1 إلى i. فـ ++i (الزيادة المسبقة) تزيد القيمة أولًا ثم تُرجع القيمة الجديدة؛ أما i++ (الزيادة اللاحقة) فتُرجع القيمة القديمة ثم تزيدها. وعندما يهمّك الأثر الجانبي فقط، فضّل ++i.

Coddy programming languages illustration

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

ابدأ الآن