سؤال

بضعة أيام مرة أخرى كان هناك مناقشة هنا حول ما إذا كان التعبير

i = ++ i + 1

يستدعي UB (السلوك غير محدد) أم لا.

أخيرا، اتخذ الاستنتاج أنه يستدعي UB حيث أن قيمة "أنا" تتغير أكثر من مرة بين نقطتين التسلسلين.

كنت متورطا في مناقشة مع يوهانس شوب في هذا الموضوع نفسه. وفقا له

i = (i، i ++، I) +1 ------ (1) / * يستدعي UB وكذلك * /

قلت (1) لا يستدعي UB لأن الآثار الجانبية للتفضيل الفرعي السابق يتم مسحها من قبل مشغل الفاصلة "،" بين I و I ++ وبين I ++ وأنا.

ثم أعطى التفسير التالي:

"نعم نقطة التسلسل بعد i ++ يكمل جميع الآثار الجانبية قبل ذلك، ولكن لا يوجد شيء يتوقف عن التأثير الجانبي المهمة المتداخلة مع التأثير الجانبي ل I ++.المشكلة الأساسية هي أن التأثير الجانبي للمهالة غير محددة يحدث بعد أو قبل تقييم كل من المعاملتين في المهمة، وبالتالي فإن نقاط التسلسل لا يمكن أن تفعل أي شيء فيما يتعلق بحماية هذا: نقاط التسلسل تحفز أمرا جزئيا: فقط ل هناك نقطة تسلسل بعد وقبل I ++ لا يعني أن جميع الآثار الجانبية تسلسل فيما يتعلق.

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

البيان المكتوب في "جريئة" مرتبك لي. على حد علمى:

"في بعض النقاط المحددة في تسلسل التنفيذ يسمى نقاط التسلسل، يجب إكمال جميع الآثار الجانبية للتقييمات السابقة ولا توجد آثار جانبية للتقييمات اللاحقة قد حدثت".

منذ ذلك الحين، حدد مشغلون الفاصلة أيضا أمر الإعدام تم إلغاء التأثير الجانبي ل i ++ عندما نصل إلى آخر I.HE (Johannes) كان من الممكن تحديد أمر التقييم (ولكن في حالة مشغل الفاصلة هو محدد جيدا ).

لذلك أريد فقط أن أعرف ما إذا كان (1) يستدعي UB أم لا؟ هل يمكن لشخص ما تقديم شرح آخر صالح؟

شكرا!

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

المحلول

يقول قياسي C هذا عن مشغلي المهام المهمة (C90 6.3.16 أو C99 6.5.16):

يحدث التأثير الجانبي لتحديث القيمة المخزنة للعامل الأيسر بين نقطة التسلسل السابقة والآخر.

يبدو لي أنه في البيان:

i=(i,i++,i)+1;

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

ومع ذلك، هذا التعبير:

*(some_ptr + i) = (i,i++,i)+1;

سيكون له سلوك غير محدد لأن ترتيب تقييم المعاملتين 2 لمشغل التعيين غير محدد، وفي هذه الحالة بدلا من المشكلة في الوقت الحالي عندما يحدث التأثير الجانبي لمشغل الواجب، فإن المشكلة لا تعرف ما إذا كانت قيمة لقد استخدمت في معامل المقبض الأيسر سيتم تقييمها قبل أو بعد الجانب الأيمن. لا يحدث ترتيب مشكلة التقييم هذا في المثال الأول لأنه في هذا التعبير قيمة i لم يتم استخدامه بالفعل في الجانب الأيسر - كل ما يهتم بمشغل المهمة هو "NESS LVALUE" i.

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

نصائح أخرى

أعتقد أن التعبير التالي لديه بالتأكيد سلوك غير محدد.

i + ((i, i++, i) + 1)

والسبب هو أن مشغل الفاصلة يحدد نقاط التسلسل بين الأسرع في قوسين، ولكن لا يحدد أين في هذا التسلسل تقييم معامل اليد اليسرى + يحدث. أحد الاحتمالات بين نقاط التسلسل المحيطة i++ وهذا ينتهك 5/4 كما i مكتوب على ما بين نقطتين التسلسلين ولكن يتم قراءة أيضا مرتين بين نفس نقاط التسلسل وليس فقط لتحديد القيمة المراد تخزينها ولكن أيضا لتحديد قيمة المعامل الأول إلى + المشغل أو العامل.

هذا لديه أيضا سلوك غير محدد.

i += (i, i++, i) + 1;

الآن، أنا لست متأكدا من هذا البيان.

i = (i, i++, i) + 1;

على الرغم من تطبيق نفس المديرين، i يجب أن تكون "تقييمها" باعتبارها lvalue قابلة للتعديل ويمكن القيام بذلك في أي وقت، لكنني لست مقتنعا بذلك القيمة حتى يكون اقرأ كجزء من هذا. (أو هل هناك تقييد آخر على أن التعبير ينتهك أن يسبب UB؟)

التعبير الفرعي (i, i++, i) يحدث كجزء من تحديد القيمة المراد تخزينها وأن التعبير الفرعي يحتوي على نقطة تسلسل بعد تخزين قيمة i. وبعد لا أرى أي طريقة لا تتطلب هذا التأثير الجانبي i++ لتكون كاملة قبل تحديد القيمة المراد تخزينها، وبالتالي النقطة الممكنة في أقرب وقت يمكن أن يحدث تأثير جانبي المهمة.

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

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

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

لغة لطيفة سودوكو، رغم ذلك. :-)

تحرير: هناك تفسير أكثر تفصيلا هنا.

كنت مرتبكا في البداية فيما يتعلق ببيان يوهانس (Litb) لكنه ذكر ذلك في:

i = (i, ++i, i) +1

<يونانيس>
إذا كانت <a> هي مهمة، فهي زيادة. :s: هي نقطة تسلسل، ثم يمكن أن تتسلسل الآثار الجانبية على النحو التالي بين نقاط التسلسل: (i :s: i++< a ><n> :s: i) + 1. وبعد قيمة العددية i تم تغيير مرتين بين نقطة التسلسل الأولى والثانية هنا. النظام الذي يحدث فيه المهمة والزيادة غير محددة، وبالتالي بينها لا توجد نقطة تسلسل، فهي ليست ذرية حتى فيما يتعلق ببعضها البعض. هذا هو المرء السماح بالطلب المسموح به من خلال الطلب غير المحدد لهذه الآثار الجانبية.

هذا يختلف (i++, i++), ، نظرا لأن أمر تقييم الفرعي الفرعي هو من اليسار إلى اليمين، وفي نقطة التسلسل بينهما، يجب إكمال زيادة التقييم السابق، ولا يجوز الزيادة التالية بعد. هذا يفرض أنه لا يوجد تغيير في قيمة i بين نقطتين التسلسلين، مما يجعل (i++, i++) صالح
</ johannes>

هذا جعلني أعتقد أن التسلسل المذكور من LITB غير صالح لأنه لكل C99:

6.5.16.1 (2) في مهمة بسيطة (=)، يتم تحويل قيمة المعامل الصحيح إلى نوع تعبير المهمة واستبدال القيمة المخزنة في الكائن المعين بواسطة المعامل الأيسر.

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

6.5.17 (2) يتم تقييم المعامل الأيسر لمشغل الفاصلة كتعبير باطلة؛ هناك نقطة تسلسل بعد تقييمها. ثم يتم تقييم المعامل الصحيح؛ النتيجة لها نوع وقيمتها.

أي يحتاج إلى تقييم أقصى اليمين لعملية الفاصلة لمعرفة قيمة ونوع تعبير الفاصلة (وقيمة المعامل الصحيح على مثالي).

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

يرجى تصحيح لي إذا كنت مخطئا.


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