يقيد

في لغة البرمجة C ، restrictيُعدّ `<input type="type">` مُحدِّدًا للنوع يُمكن تطبيقه على المؤشر لإعلام المُصرِّف بأنه طوال فترة صلاحية هذا المؤشر، لن يُستخدم أي مؤشر آخر للوصول إلى نفس الكائن المُشار إليه. هذا يُحدِّد من تأثيرات تعدد أسماء المؤشرات ، مما يسمح للمُصرِّف بإجراء تحسينات (مثل التوجيه ) التي لم تكن لتُجرى لولا ذلك. ينتج عن عدم اتباع تعريف النية والوصول إلى الكائن بواسطة مؤشر مستقل سلوك غير مُعرَّف .

تم تقديم هذه restrictالكلمة المفتاحية بواسطة معيار C99 . على الرغم من أن لغة C++ تدعم معظم ميزات لغة C ، restrictإلا أنها غير مدرجة في معيار C++.

تحسين

إذا علم المترجم بوجود مؤشر واحد فقط إلى كتلة ذاكرة، فإنه يستطيع إنتاج كود مُحسَّن بشكل أفضل. على سبيل المثال، في دالة updatePointers()تضيف قيمة xإلى كل من وسيطيها aو b:

void updatePointers ( size_t * a , size_t * b , size_t * x ) { * a += * x ; * b += * x ; }

في الكود أعلاه، قد تشير المؤشرات aو bو إلى نفس موقع الذاكرة ، لذلك قد يقوم المترجم بتوليد كود أقل كفاءة:x

آلة RISC افتراضية. ldr r12 , [ x ] ; تحميل الذاكرة من الموقع x إلى r12. ldr r3 , [ a ] ; تحميل الذاكرة من الموقع a إلى r3. add r3 , r3 , r12 ; إجراء عملية الجمع: r3 = r3 + r12. str r3 , [ a ] ; تخزين r3 في موقع الذاكرة a، مع تحديث القيمة. ldr r3 , [ b ] ; قد يتطلب الأمر 'load' الانتظار حتى اكتمال عملية 'store' السابقة. ldr r12 , [ x ] ; يجب التحميل مرة ثانية لضمان الاتساق. add r3 , r3 , r12 str r3 , [ b ]

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

void updatePointers ( size_t * restrict a , size_t * restrict b , size_t * restrict x ) { * a += * x ; * b += * x ; }

عندئذٍ، يُسمح للمُصرّف بافتراض أنَّ aو bو xتشير إلى مواقع مختلفة، وأنَّ تحديث موقع الذاكرة الذي يُشير إليه أحد المؤشرات لن يؤثر على مواقع الذاكرة التي تُشير إليها المؤشرات الأخرى. يقع على عاتق المُبرمج، وليس المُصرّف، مسؤولية ضمان عدم إشارة المؤشرات إلى مواقع مُتطابقة. يُمكن للمُصرّف، على سبيل المثال، إعادة ترتيب الكود، بتحميل جميع مواقع الذاكرة أولًا، ثم تنفيذ العمليات قبل حفظ النتائج في الذاكرة.

ldr r12 , [ x ] ; لاحظ أن x يتم تحميله مرة واحدة فقط الآن. ldr r3 , [ a ] ​​; أيضًا، جميع عمليات التحميل في البداية ... ldr r4 , [ b ] add r3 , r3 , r12 add r4 , r4 , r12 str r3 , [ a ] ​​; ... جميع عمليات التخزين في النهاية. str r4 , [ b ]

إنّ كود التجميع أعلاه أقصر لأنّ xالدالة تُحمّل مرة واحدة فقط. وبدون xقيود، يُمكن aللدالة أن تُنشئ اسمًا بديلًا لها. سيؤدي هذا إلى xتغيير قيمة الدالة عند أول إضافة، عند aتحديث الدالة، وبالتالي الحاجة إلى إعادة تحميلها. كما أنّ كود التجميع أعلاه أسرع، لأنّ المُصرّف يُمكنه إعادة ترتيب الكود بحرية أكبر. في الإصدار الثاني من المثال أعلاه، storeتُنفّذ جميع العمليات بعد العمليات loadالأخرى، مما يضمن عدم اضطرار المعالج إلى التوقف في منتصف الكود لانتظار اكتمال العمليات store. يُمكن إعادة ترتيب الكود لأنّ المؤشرين aو bمُعلّمان بـ restrict، مما يضمن عدم استدعاء المستخدم للدالة مع وجود اسم بديل لهذين المؤشرين، متوقعًا xإضافة قيمة الدالة مرتين إلى العدد الصحيح الذي يُشيران إليه.

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

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

دعم من قبل مترجمات لغة C++

لا تدعم لغة C++restrict الكلمات المفتاحية البديلة بشكل قياسي ، ولكن العديد من المترجمات توفر بدائل تعمل عادةً في كلٍ من C++ وC، مثل مترجمات GCC و Clang__restrict__ و Visual C++ . __declspec(restrict)بالإضافة إلى ذلك، __restrictتدعم هذه المترجمات الثلاثة الكلمات المفتاحية البديلة. ويختلف التفسير الدقيق لهذه الكلمات المفتاحية البديلة باختلاف المترجم.

  • في مُجمِّعات أنظمة يونكس مثل GCC وClang، __restrictتعني هذه __restrict__المصطلحات نفس المعنى تمامًا كما في نظيراتها في لغة C. وتشمل الإضافات السماح بتطبيقها على أنواع المراجع و this. [ 1 ]
  • في لغة Visual C++، يتم توفير العديد من المحددات التي لا تحتوي على أسماء مستعارة:
    1. __declspec(restrict)ينطبق ذلك على تعريف الدالة ويشير إلى أن المؤشر المُعاد ليس له اسم مستعار.
    2. __restrictيُستخدم في نفس المكان الذي يُستخدم فيه restrict، ولكن تلميح عدم وجود اسم بديل لا ينتشر كما في restrict. كما أنه مُوسّع لأنواع الاتحاد .

restrictيظل قابلاً للاستخدام في سياق ( الربط C ).extern"C"

تحذيرات المُصرّف

للمساعدة في منع حدوث أخطاء برمجية، تحاول بعض المترجمات والأدوات الأخرى اكتشاف متى تم تمرير وسائط متداخلة إلى الدوال ذات المعاملات المميزة بعلامة restrict. [ 2 ] يعتبر معيار CERT C للبرمجة إساءة استخدام هذه العلامة ودوالrestrict المكتبات المميزة بها (EXP43-C) مصدرًا محتملاً لأخطاء البرمجيات.

مراجع

  1. "المؤشرات المقيدة" . استخدام مجموعة مترجمات جنو (GCC) .
  2. "خيارات التحذير: -Wrestrict" . GCC . تم الاسترجاع في 19 نوفمبر 2019 .