سؤال

يمكن للشخص أن يفسر لي لماذا هذا الكود يطبع 14?أنا فقط طلبت من قبل طالب آخر و لا يمكن أن الرقم بها.

int i = 5;
i = ++i + ++i;
cout<<i;
هل كانت مفيدة؟

المحلول

وترتيب الآثار الجانبية غير معرف في C ++. بالإضافة إلى ذلك، تعديل متغير مرتين في تعبير واحد ليس لديه سلوك محددة (انظر في C ++ القياسية، §5.0.4، الصفحة الجسدية 87 / منطقية الصفحة 73).

والحل: لا تستخدم آثار جانبية في التعبير معقد، لا تستخدم أكثر من واحد من تلك بسيطة. وأنها لا تؤذي لتمكين كل التحذيرات المترجم يمكن أن تعطي لك: إضافة -Wall (دول مجلس التعاون الخليجي) أو /Wall /W4 (البصرية C ++) إلى سطر الأوامر تعطي تحذيرا المناسب:

test-so-side-effects.c: In function 'main':
test-so-side-effects.c:5: warning: operation on 'i' may be undefined
test-so-side-effects.c:5: warning: operation on 'i' may be undefined

من الواضح، رمز يجمع إلى:

i = i + 1;
i = i + 1;
i = i + i;

نصائح أخرى

هذا غير معروف السلوك ، فإن النتيجة سوف تختلف اعتمادا على المترجم استخدام.انظر ، على سبيل المثال ، C++ التعليمات لايت.

في بعض الإجابات/التعليقات كان هناك نقاش حول معنى 'undefined السلوك' وما إذا كان هذا يجعل البرنامج غير صالح.لذلك أنا نشر هذا الطويلة بدلا الإجابة بالتفصيل بالضبط ما القياسية يقول مع بعض الملاحظات.آمل انها ليست مملة جدا...

ونقلت بت القياسية تأتي من التيار C++ القياسية (ISO/IEC 14882:2003).هناك عبارات مماثلة في ج القياسية.

وفقا C++ القياسية تعديل قيمة أكثر من مرة في مجموعة من تسلسل النقاط النتائج في السلوك غير معرف (المادة 5 الفقرة 4):

إلا حيث لوحظ ، من اجل تقييم المعاملات الفردية مشغلي subexpressions من فرد التعبير ، في الجانب الذي تجري الآثار ، غير محدد.53) بين السابق و تسلسل المقبل النقطة العددية كائن يكون القيمة المخزنة تعديل على الأكثر مرة واحدة من قبل تقييم التعبير.علاوة على ذلك, قبل القيمة يجب أن تكون الوصول إليها فقط لتحديد قيمة ليتم تخزينها.متطلبات هذا الفقرة يجب أن تتحقق لكل المسموح به ترتيب subexpressions كامل التعبير ؛ وإلا فإن سلوك غير معرف.[على سبيل المثال:

i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented

المثال]

نلاحظ أن المثال الثاني،"i = 7, i++, i++;"يعرف منذ فاصلة المشغل هو تسلسل نقطة.

هنا ما C++ القياسية يقول 'undefined السلوك' يعني:

1.3.12 السلوك غير معرف [defns.غير معروف]

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

وبعبارة أخرى ، فإن المترجم هو حر في أن يفعل ما يريد ، بما في ذلك

  1. بصق رسالة خطأ ،
  2. تفعل شيئا تنفيذ محددة و موثقة ،
  3. وقد لا يمكن التنبؤ بها تماما النتائج

البند الثاني يشمل اللغة امتداد معظم المجمعين ، ولكن بالطبع ليست معرفة في معيار.

لذا أعتقد أنه بالمعنى الدقيق للكلمة شيء أن يسلك السلوك غير معرف ليس "غير قانونية" ، ولكن في تجربتي كلما كان هناك شيء في C/C++ برنامج المعارض 'undefined السلوك' (إلا إذا كان التمديد) - انها علة.أعتقد أن استدعاء مثل هذه بناء غير قانونية ليست مربكة ، أو مضللة ، أو مضللة.

أيضا, أعتقد أن محاولة لشرح ما المترجم يقوم به للوصول إلى قيمة 14 ليست مفيدة بشكل خاص, كما أنه يخطئ الهدف.المترجم يمكن أن تفعل أي شيء تقريبا ؛ في الواقع, فمن المحتمل أن المترجم قد تصل إلى نتيجة مختلفة عند تشغيله باستخدام اختلاف خيارات التحسين (أو قد تنتج البرمجية التي تعطل - من يدري؟).

بالنسبة لأولئك الذين يريدون بعض مراجع إضافية أو نداء إلى السلطة ، وفيما يلي بعض المؤشرات:

ستيف القمة (معيل من شركات.لانغ.ج: أسئلة وأجوبة) طويلة الإجابة على هذا الموضوع من عام 1995:

هنا ما Bjarne Stroustrup أن يقول في هذا الشأن:


الحاشية:C++ القياسية يستخدم كلمة "غير قانونية" بالضبط مرة واحدة - عندما تصف الفرق بين C++ و C القياسية فيما يتعلق باستخدام static أو extern مع نوع الإعلانات.

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

إذا كنت تفعل

int j=++i; 
int k=++i;

i = j+k;

سترى 13 كما هو متوقع.

في المترجم الخاص بك معين، فإنه يختار أن تفعل كل من ++ عمليات أولا، ثم الإضافة. انها تفسير رمز على النحو التالي:

int i = 5;
++i;
++i;
i = i + i;
cout << i;

وهذا صحيح تماما.

ومن شأن مسألة أفضل أن يكون، ودائما على وشك أن 14؟

int i = 5;
i = ++i + ++i;
cout<<i;

i = ++i   + ++i   ;
i = ++(5) + ++(5) ;
i =    6  +    6  ;
i = 12;

i = ++i   + ++i   ;
i = ++i   + ++(5) ;
i = ++i   +   (6) ;
i = ++(6) +    6  ;
i =   (7) +    6  ;
i = 13;

i = ++i   + ++i   ;
i = ++i   + ++(5) ;
i = ++(6) +   (6) ;
i =   (7) +   (7) ;
i = 14;

في جميع الاحتمالات أنه من المحتمل أن 14، لأنه يجعل <م> قليلا أكثر منطقية.

وأعتقد أنه عندما ننظر إلى المشكلة من عيني شجرة غوي، والإجابة على المشكلة تصبح أكثر وضوحا:

وأنا
|
=
|
+
|
التعبير أحادي - التعبير أحادي

أحادي التعبير: عامل أحادي التعبير

في حالتنا يغلي التعبير وصولا الى متغير ط.

الآن ما يحدث هو أن كلا من التعبير أحادي تعديل نفس المعامل، حتى لا رمز مرتين ++ أنا عند تقييم التعبيرات الأحادية قبل إضافة نتائج كل التعابير الأحادية.

وماذا في ذلك رمز يفعل هو في الواقع

++ الأول؛
++ الأول؛
ط = أنا + أنا،

لأني = 5 وهذا يعني

ط = ط + 1؛ // I <- 6
ط = ط + 1؛ // I <- 7 <ر> ط = أنا + أنا. // I <- 14 <ر>

ولأن الزيادة بادئة لها الأسبقية:

int i = 5;
i = i+1; // First ++i, i is now 6
i = i+1; // Second ++i, i is now 7
i = i + i // i = 7 + 7
cout << i // i = 14
 i = i++ + i; //11  

 i = i++ + i++; //12

 i = i++ + ++i; //13

 i = ++i + i++; //13

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