عند استخدام مؤشر تقييد في C ، هل من المقبول تغيير متغير باستخدام معرفه الأولي؟
-
30-09-2019 - |
سؤال
عند استخدام restrict
المؤشر في C ، هل من المقبول تغيير المتغير باستخدامه الأولي المعرف؟ فمثلا:
int foo = 0;
int * restrict fooPtr = &foo;
++(*fooPtr); // Part 1: foo is 1 (OK)
++foo; // Part 2: foo is 2 (Is this OK?)
int * fooPtr2 = &foo;
++(*fooPtr2); // Part 3: foo is 3 (BAD: You shouldn't access via a second pointer)
... لقد غيرت قيمة فو عبر فو بعد restrict
fooptr تم انشائه.
الجزء 1 تبدو جيدة بالنسبة لي. أنا مرتبك الجزء 2. ومن ما أفهمه restrict
, الجزء 3 سيء (يسمح برنامج التحويل البرمجي ، لكن سلوكه غير محدد ، ويعود الأمر إلى المبرمج حتى لا يفعل ذلك).
المحلول
لا ، الجزء 2 ليس على ما يرام.
الجزء المحدد من المعيار هو 6.7.3.1/4. هذا القسم كثيف إلى حد ما ، ويأخذ بعض عمليات إعادة القراءة ، ولكن P هو مؤشر مقيد ، و X هو بعض الكائنات التي يتم استخدامها للوصول إليها ، والتي يتم تعديلها. لذلك في مثالك P هو fooPtr
و x هو foo
. ثم:
يجب على كل lvalue الأخرى المستخدمة للوصول إلى قيمة x أيضًا عنوانها على أساس P.
يتم تعريف "استنادًا إلى" في الفقرة السابقة ، ولتلخيص ، Lvalue foo
يفعل ليس احصل على عنوانه بناءً على مؤشر تقييد P. بحيث يتم كسر القاعدة عند الوصول إلى الكائن foo
من خلال اسمها الخاص.
الجزء 3 ليس على ما يرام لنفس السبب بالضبط ، lvalue *fooPtr2
لا يعتمد على p أيضًا ، ولكنه يستخدم أيضًا للوصول إلى X.
أقول "ليس موافق" - أن تكون دقيقًا ، يثير مزيج 1+2 سلوكًا غير محدد ، وكذلك مزيج 1+3. طالما أنك لا تصل فعليًا إلى الكائن من خلال مؤشر تقييد ، فإن أيًا من تعريف تقييد "الركلات". إذا أردت أن تتمكن من إزالة الجزء 1 ، والاحتفاظ بمؤشر تقييد غير المستخدم ، ثم 2 و 3 سيكونان على ما يرام.
نصائح أخرى
نعم ، "الجزء 3" هو سلوك غير محدد. من المواصفات C99 (6.7.3 ، الفقرة 7):
إن الكائن الذي يتم الوصول إليه من خلال مؤشر مقيد في Quali له علاقة خاصة مع هذا المؤشر. يتطلب هذا الارتباط ، الذي تم تحديده في 6.7.3.1 أدناه ، أن يستخدم كل ما يصل إلى هذا الكائن ، بشكل مباشر أو غير مباشر ، قيمة هذا المؤشر المحدد.
أود أن أقول #2 سيئة. على سبيل المثال ، قد يتحسن برنامج التحويل البرمجي عن طريق تحميل القيمة في *fooptr في سجل ، ثم اكتب قيمة التسجيل مرة أخرى إلى Foo مرة أخرى لاحقًا - بعد أن يتم فقد ++ foo.
على افتراض أن جميع الأجزاء من سؤالك تحدث في نفس الكتلة ، ليس من المقبول الوصول إلى قيمة foo
مباشرة (الجزء 2) ولا للوصول إليه عبر مؤشر آخر (الجزء 3):
- 6.7.3.1 التعريف الرسمي للتقييد
يجب على كل lvalue الأخرى المستخدمة للوصول إلى قيمة x أيضًا عنوانها على أساس P.
التعريف الرسمي ل restrict
من الصعب للغاية المتابعة (على الأقل بالنسبة لي) ، ولكن الوصف الأقل الرسمي التالي أيضًا من المبالغ القياسية بشكل جيد (على الأقل لهذه الحالة):
إن الكائن الذي يتم الوصول إليه من خلال مؤشر مؤهل للتأهل له ارتباط خاص مع هذا المؤشر. يتطلب هذا الارتباط ، المحدد في 6.7.3.1 أدناه ، أن يستخدم جميع الوصول إلى هذا الكائن ، بشكل مباشر أو غير مباشر ، قيمة هذا المؤشر بالذات.