استخدام عوامل تشغيل bitwise للقيم المنطقية في C++

StackOverflow https://stackoverflow.com/questions/24542

  •  09-06-2019
  •  | 
  •  

سؤال

هل هناك أي سبب لعدم استخدام عوامل تشغيل البت & و | و ^ للقيم "المنطقية" في C++؟

أواجه أحيانًا مواقف أريد فيها أن يكون أحد الشرطين صحيحًا (XOR)، لذلك أقوم فقط بإدخال عامل التشغيل ^ في تعبير شرطي.أرغب أيضًا في بعض الأحيان في تقييم جميع أجزاء الشرط سواء كانت النتيجة صحيحة أم لا (بدلاً من قصر الدائرة)، لذلك أستخدم & و |.أحتاج أيضًا إلى تجميع القيم المنطقية في بعض الأحيان، ويمكن أن يكون &= و |= مفيدًا جدًا.

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

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

المحلول

|| و && هي عوامل تشغيل منطقية، ويضمن إرجاع العوامل المضمنة أيضًا true أو false.لا شيء آخر.

|, & و ^ هي عوامل تشغيل bitwise.عندما يكون مجال الأرقام التي تعمل عليها هو 1 و0 فقط، فهي متماثلة تمامًا، ولكن في الحالات التي لا تكون فيها القيم المنطقية 1 و0 بشكل صارم - كما هو الحال مع لغة C - قد ينتهي بك الأمر إلى بعض السلوك أنت لا تريد.على سبيل المثال:

BOOL two = 2;
BOOL one = 1;
BOOL and = two & one;   //and = 0
BOOL cand = two && one; //cand = 1

في C++، ومع ذلك، bool النوع مضمون أن يكون إما أ true أو أ false (والتي تحويل ضمنيا إلى على التوالي 1 و 0)، لذلك لا داعي للقلق من هذا الموقف، ولكن حقيقة أن الأشخاص غير معتادين على رؤية مثل هذه الأشياء في التعليمات البرمجية تشكل حجة جيدة لعدم القيام بذلك.فقط قل b = b && x ويتم الانتهاء من ذلك.

نصائح أخرى

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

bitwise xor != xor المنطقي (باستثناء 0 و1)

أولاً، إذا كنت تعمل على قيم أخرى غير false و true (أو 0 و 1, ، كأعداد صحيحة)، و ^ يمكن للمشغل تقديم سلوك لا يعادل xor المنطقي.على سبيل المثال:

int one = 1;
int two = 2;

// bitwise xor
if (one ^ two)
{
  // executes because expression = 3 and any non-zero integer evaluates to true
}

// logical xor; more correctly would be coded as
//   if (bool(one) != bool(two))
// but spelled out to be explicit in the context of the problem
if ((one && !two) || (!one && two))
{
  // does not execute b/c expression = ((true && false) || (false && true))
  // which evaluates to false
}

الفضل للمستخدمPatrick للتعبير عن هذا أولاً.

ترتيب العمليات

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

بعبارة أخرى

bool result = true;
result = result && a() && b();
// will not call a() if result false, will not call b() if result or a() false

لن يعطي دائمًا نفس النتيجة (أو الحالة النهائية) مثل

bool result = true;
result &= (a() & b());
// a() and b() both will be called, but not necessarily in that order in an
// optimizing compiler

وهذا مهم بشكل خاص لأنه لا يجوز لك التحكم في الأساليب a() و b(), ، أو قد يأتي شخص آخر ويغيرها لاحقًا دون أن يفهم التبعية، ويتسبب في حدوث خطأ سيئ (وغالبًا ما يكون إصدار الإصدار فقط).

أظن

a != b

هو ما تريد

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

مساوئ مشغلي مستوى البت.

أنت تسأل:

"هل هناك أي سبب لعدم استخدام عوامل تشغيل bitwise &, |, ، و ^ لقيم "منطقية" في C++؟"

نعم العوامل المنطقية, ، هذا هو المشغلون المنطقيون المدمجون عالي المستوى !, && و ||, ، تقدم المزايا التالية:

  • مضمون تحويل الحجج ل bool, ، أي.ل 0 و 1 القيمة الترتيبية.

  • مضمون تقييم ماس كهربائى حيث يتوقف تقييم التعبير بمجرد معرفة النتيجة النهائية.
    يمكن تفسير ذلك على أنه منطق قيمة الشجرة حقيقي, خطأ شنيع و غير محدد.

  • معادلات نصية قابلة للقراءة not, and و or, ، حتى لو لم أستخدمها بنفسي.
    كما يلاحظ القارئ أنتيموني في تعليق، فإن مشغلي مستوى البت لديهم رموز بديلة، وهي bitand, bitor, xor و compl, ، ولكن في رأيي هذه أقل قابلية للقراءة من and, or و not.

ببساطة، كل ميزة من هذه المزايا للمشغلين ذوي المستوى العالي هي عيب لمشغلي مستوى البت.

على وجه الخصوص، نظرًا لأن عوامل تشغيل البت تفتقر إلى تحويل الوسيطة إلى 0/1، فستحصل على سبيل المثال. 1 & 20, ، بينما 1 && 2true.أيضًا ^, ، حصريًا على مستوى البت، أو يمكن أن يسيء التصرف بهذه الطريقة.تعتبر القيمتين المنطقيتين 1 و 2 متماثلتين، أي true, ، ولكن تعتبر مختلفة عن أنماط البت.


كيفية التعبير المنطقي إما او في سي ++.

ثم تقوم بتقديم القليل من الخلفية للسؤال،

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

حسنا، مشغلي bitwise لديهم أسبقية أعلى من العوامل المنطقية.وهذا يعني على وجه الخصوص أنه في تعبير مختلط مثل

a && b ^ c

تحصل على النتيجة غير المتوقعة ربما a && (b ^ c).

بدلا من الكتابة فقط

(a && b) != c

التعبير بشكل أكثر إيجازا عما تقصده.

بالنسبة للحجة المتعددة إما او لا يوجد مشغل C++ يقوم بهذه المهمة.على سبيل المثال، إذا كنت تكتب a ^ b ^ c من ذلك ليس تعبيرًا يقول "إما". a, b أو c صحيح".بدلاً من ذلك تقول: "عدد فردي من a, b و c "صحيح" ، والذي قد يكون واحدًا منهم أو الثلاثة جميعًا ...

للتعبير عن العام إما/أو متى a, b و c هي من النوع bool, ، اكتب فقط

(a + b + c) == 1

أو مع عدمbool الحجج، وتحويلها إلى bool:

(!!a + !!b + !!c) == 1


استخدام &= لتجميع النتائج المنطقية.

ولك مزيد من التفصيل،

"أحتاج أيضًا إلى تجميع القيم المنطقية في بعض الأحيان، و &= و |=? يمكن أن تكون مفيدة للغاية."

حسنا، هذا يتوافق مع التحقق مما إذا كان على التوالي الجميع أو أي الحالة مرضية، و قانون دي مورغان يخبرك بكيفية الانتقال من واحدة إلى أخرى.أي.ما عليك سوى واحد منهم.يمكنك من حيث المبدأ استخدام *= ك &&=-operator (كما اكتشف جورج بول القديم، منطقي ويمكن التعبير عنه بسهولة بالضرب)، لكنني أعتقد أن ذلك من شأنه أن يحير وربما يضلل القائمين على الكود.

ضع في اعتبارك أيضًا:

struct Bool
{
    bool    value;

    void operator&=( bool const v ) { value = value && v; }
    operator bool() const { return value; }
};

#include <iostream>

int main()
{
    using namespace std;

    Bool a  = {true};
    a &= true || false;
    a &= 1234;
    cout << boolalpha << a << endl;

    bool b = {true};
    b &= true || false;
    b &= 1234;
    cout << boolalpha << b << endl;
}

الإخراج باستخدام Visual C++ 11.0 وg++ 4.7.1:

true
false

سبب الاختلاف في النتائج هو مستوى البت &= لا يوفر التحويل إلى bool من حجة الجانب الأيمن.

إذن، أي من هذه النتائج ترغب في استخدامها؟ &=?

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

على عكس إجابة باتريك، لا تحتوي لغة C++ على أي شيء ^^ مشغل لأداء ماس كهربائى حصريا أو.إذا فكرت في الأمر للحظة، فستجد أن لديك ^^ المشغل لن يكون له معنى على أي حال:مع حصري أو، تعتمد النتيجة دائمًا على كلا المعاملين.ومع ذلك، فإن تحذير باتريك بشأن عدمbool الأنواع "المنطقية" تصمد بشكل متساوٍ عند المقارنة 1 & 2 ل 1 && 2.أحد الأمثلة الكلاسيكية على ذلك هو Windows GetMessage() وظيفة، والتي ترجع حالة ثلاثية BOOL:غير صفرية، 0, ، أو -1.

استخدام & بدلاً من && و | بدلاً من || هذا ليس خطأ مطبعي غير شائع، لذلك إذا كنت تفعل ذلك عن عمد، فإنه يستحق تعليقًا يوضح السبب.

لقد قدم باتريك نقاطاً جيدة، ولن أكررها.ومع ذلك، قد أقترح تقليل عبارات "if" إلى لغة إنجليزية قابلة للقراءة حيثما أمكن ذلك باستخدام vars منطقية جيدة التسمية. على سبيل المثال، وهذا يستخدم عوامل تشغيل منطقية ولكن يمكنك أيضًا استخدام bitwise وتسمية المنطقيات بشكل مناسب:

bool onlyAIsTrue = (a && !b); // you could use bitwise XOR here
bool onlyBIsTrue = (b && !a); // and not need this second line
if (onlyAIsTrue || onlyBIsTrue)
{
 .. stuff ..
}

قد تعتقد أن استخدام القيمة المنطقية يبدو غير ضروري، ولكنه يساعد في أمرين رئيسيين:

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

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

IIRC، سوف يحذر العديد من مترجمي C++ عند محاولة تحويل نتيجة عملية البت إلى نتيجة منطقية.سيكون عليك استخدام نوع المصبوب لجعل المترجم سعيدًا.

إن استخدام عملية البت في تعبير if من شأنه أن يخدم نفس النقد، ولكن ربما ليس من قبل المترجم.أي قيمة غير الصفر تعتبر صحيحة، لذا فإن شيئًا مثل "if (7 & 3)" سيكون صحيحًا.قد يكون هذا السلوك مقبولاً في لغة Perl، لكن لغة C/C++ هي لغات صريحة جدًا.أعتقد أن الحاجب سبوك هو العناية الواجبة.:) أود أن ألحق "== 0" أو "!= 0" لتوضيح هدفك تمامًا.

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

يساعد استخدام عمليات bitwise لـ bool في حفظ منطق تنبؤ الفرع غير الضروري بواسطة المعالج، الناتج عن تعليمات 'cmp' التي يتم جلبها بواسطة العمليات المنطقية.

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

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

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