الإرسال الديناميكي

في علوم الحاسوب ، يُعرف الإرسال الديناميكي بأنه عملية اختيار أي تنفيذ لعملية متعددة الأشكال ( طريقة أو دالة) يتم استدعاؤه أثناء وقت التشغيل . ويُستخدم هذا الأسلوب بشكل شائع في لغات وأنظمة البرمجة كائنية التوجه (OOP)، ويُعتبر سمة أساسية لها. [ 1 ]

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

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

يختلف الإرسال الديناميكي عن الربط المتأخر (المعروف أيضًا بالربط الديناميكي). يربط الربط بالاسم اسمًا بعملية معينة. للعملية متعددة الأشكال عدة تطبيقات، جميعها مرتبطة بالاسم نفسه. يمكن إجراء عمليات الربط في وقت الترجمة أو (مع الربط المتأخر) في وقت التشغيل. في الإرسال الديناميكي، يتم اختيار تطبيق معين للعملية في وقت التشغيل. بينما لا يستلزم الإرسال الديناميكي الربط المتأخر، فإن الربط المتأخر يستلزم الإرسال الديناميكي، لأن تطبيق العملية المرتبطة متأخرًا لا يُعرف إلا في وقت التشغيل.

الآليات

إرسال فردي ومتعدد

قد يعتمد اختيار إصدار الدالة المراد استدعاؤها إما على كائن واحد أو على مجموعة من الكائنات. يُطلق على الأول اسم " الاستدعاء الفردي" وهو مدعوم مباشرةً من لغات البرمجة الكائنية الشائعة مثل Smalltalk و C++ و Java و C# و Objective-C و Swift و JavaScript و Python . في هذه اللغات واللغات المشابهة، يمكن استدعاء دالة القسمة باستخدام صيغة مشابهة لـ

المقسوم . يقسم ( المقسوم عليه ) # المقسوم / المقسوم عليه

حيث تكون المعاملات اختيارية. يُنظر إلى هذا على أنه إرسال رسالة باسم "divide" مع المعامل "divisor" إلى "vidived" . سيتم اختيار التنفيذ بناءً على نوع " vidived " فقط (ربما عدد كسري ، أو عدد عشري ، أو مصفوفة )، بغض النظر عن نوع أو قيمة " divisor" .

في المقابل، تقوم بعض اللغات بتوزيع الدوال أو الطرق بناءً على مجموعة المعاملات؛ ففي حالة القسمة، يحدد نوعا المقسوم والمقسوم عليه معًا عملية القسمة التي ستُجرى. يُعرف هذا بالتوزيع المتعدد . ومن أمثلة اللغات التي تدعم التوزيع المتعدد: Common Lisp و Dylan و Julia .

آليات الإرسال الديناميكية

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

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

تقدم بعض اللغات نهجاً هجيناً.

سيؤدي الإرسال الديناميكي دائمًا إلى زيادة الحمل الزائد، لذا توفر بعض اللغات إرسالًا ثابتًا لأساليب معينة.

تنفيذ بلغة C++

تستخدم لغة C++ الربط المبكر وتوفر كلاً من الإرسال الديناميكي والإرسال الثابت. الإرسال الثابت هو الشكل الافتراضي. وللحصول على إرسال ديناميكي، يجب على المبرمج تعريف الدالة على أنها افتراضية (virtual) .

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

لا يؤدي تحميل الأنواع الزائد إلى إرسال ديناميكي في لغة C++، لأن اللغة تعتبر أنواع معلمات الرسالة جزءًا من اسم الرسالة الرسمي. وهذا يعني أن اسم الرسالة الذي يراه المبرمج ليس هو الاسم الرسمي المستخدم للربط.

تنفيذ Go و Rust و Nim

في لغات البرمجة Go و Rust و Nim ، يتم استخدام شكل أكثر تنوعًا من الربط المبكر. يتم حمل مؤشرات Vtable مع مراجع الكائنات كمؤشرات "سميكة" (الواجهات في Go، أو كائنات السمات في Rust [ 3 ] [ 4 ] ).

يفصل هذا الأسلوب الواجهات المدعومة عن هياكل البيانات الأساسية. لا تحتاج كل مكتبة مُجمَّعة إلى معرفة النطاق الكامل للواجهات المدعومة لاستخدام نوع ما بشكل صحيح، بل يكفي معرفة تخطيط جدول الدوال الافتراضية (vtable) المحدد الذي تتطلبه. يمكن للبرنامج تمرير واجهات مختلفة لنفس البيانات إلى دوال مختلفة. تأتي هذه المرونة على حساب بيانات إضافية مع كل مرجع للكائن، وهو ما يُشكِّل مشكلة إذا تم تخزين العديد من هذه المراجع بشكل دائم.

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

تطبيق Smalltalk

تستخدم لغة Smalltalk مُوزِّع رسائل قائم على النوع. لكل نسخة نوع واحد يحتوي تعريفه على الدوال. عندما تتلقى نسخة رسالة، يبحث المُوزِّع عن الدالة المُقابلة في خريطة تحويل الرسائل إلى دوال للنوع، ثم يستدعي تلك الدالة.

نظرًا لأن النوع الواحد قد يحتوي على سلسلة من الأنواع الأساسية، فإن عملية البحث هذه قد تكون مكلفة. ويبدو أن تطبيقًا بسيطًا لآلية Smalltalk سيُحمّل النظام بعبء إضافي أعلى بكثير من نظيره في لغة C++، وسيُتكبّد هذا العبء الإضافي مع كل رسالة يتلقاها الكائن.

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

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

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

تستخدم العديد من اللغات الأخرى ذات الكتابة الديناميكية، بما في ذلك بايثون وروبي وأوبجكتيف سي وجروفي، أساليب مماثلة.

أمثلة

ج

لا يتم تضمين الإرسال الديناميكي في لغة C مثل اللغات الأخرى، ولكنه لا يزال ممكنًا من خلال إدارة مؤشرات الوظائف يدويًا.

#include <stdio.h> #include <stdlib.h>typedef struct Pet { const char * name ; void ( * speak )( struct Pet * ); // يحتوي على مؤشر دالة } Pet ;Pet * createPet ( const char * name , void ( * speakFunc )( Pet * )) { Pet * pet = ( Pet * ) malloc ( sizeof ( Pet )); pet -> name = name ; pet -> speak = speakFunc ; return pet ; }void destroyPet ( Pet * pet ) { free ( pet ); }void dogSpeak ( Pet * pet ) { printf ( "%s يقول 'نباح!' \n " , pet -> name ); }void catSpeak ( Pet * pet ) { printf ( "%s يقول 'مياو!' \n " , pet -> name ); }void speak ( Pet * pet ) { pet -> speak ( pet ); }int main () { Pet * fido = createPet ( "Fido" , dogSpeak ); Pet * simba = createPet ( "Simba" , catSpeak );speak ( fido ); // يستدعي dogSpeak() speak ( simba ); // يتحدث catSpeak();// تنظيف؛ تحرير الموارد destroyPet ( fido ); destroyPet ( simba ); return 0 ; }

لغة سي++

استيراد std ؛باستخدام std :: string ;// اجعل Pet فئة أساسية افتراضية مجردة class Pet { protected : string name ; public : explicit Pet ( const string & name ) : name { name } { }virtual void speak () = 0 ; };class Dog : public Pet { public : explicit Dog ( const string & name ) : Pet ( name ) {}void speak () override { std :: println ( "{} يقول 'نباح!'" , name ); } };class Cat : public Pet { public : explicit Cat ( const string & name ) : Pet ( name ) {}void speak () override { std :: println ( "{} يقول 'مياو!'" , name ); } };// ستكون الدالة speak() قادرة على قبول أي شيء مشتق من Pet void speak ( Pet & pet ) { pet . speak (); }int main () { Dog fido ( "Fido" ); Cat simba ( "Simba" ); speak ( fido ); speak ( simba ); return 0 ; }

سي شارب

namespace Wikipedia.Examples ;باستخدام النظام ؛فئة مجردة للحيوانات الأليفة { اسم محمي من نوع سلسلة نصية ؛public Pet ( string name ) { this . name = name ; }public abstract void Speak (); }class Dog : Pet { public Dog ( string name ) : base ( name ) { }public override void Speak () { Console . WriteLine ( $"{name} says 'Woof!'" ); } }class Cat : Pet { public Cat ( string name ) : base ( name ) { }public override void Speak () { Console . WriteLine ( $"{name} says 'Meow!'" ); } }public class Main { public static void Speak ( Pet pet ) { pet . Speak (); }public static void Main () { Dog fido = new ( "Fido" ); Cat simba = new ( "Simba" ); Speak ( fido ); Speak ( simba ); } }

جافا

package org.wikipedia.examples ;فئة مجردة للحيوانات الأليفة { اسم محمي من نوع سلسلة نصية ؛public Pet ( String name ) { this . name = name ; }public abstract void speak (); }class Dog extends Pet { public Dog ( String name ) { super ( name ); }@Override public void speak () { System . out . printf ( "%s يقول 'نباح!'%n" , name ); } }class Cat extends Pet { public Cat ( String name ) { super ( name ); }@Override public void speak () { System . out . printf ( "%s يقول 'مياو!'%n" , name ); } };public class Main { public static void speak ( Pet pet ) { pet . speak (); }public static void main ( String [] args ) { Dog fido = new Dog ( "Fido" ); Cat simba = new Cat ( "Simba" ); speak ( fido ); speak ( simba ); } }

بايثون

من abc استورد ABC و abstractmethod ، ومن typing استورد Never# ABC هي فئة تُستخدم للدلالة على أن الفئات التي ترث منها مباشرةً هي فئات مجردة. مثال: فئة Pet ( ABC ) : def __init __ ( self , name : str ) -> None : self.name = name@abstractmethod def speak ( self ) -> Never : raise NotImplementedError ( "يجب تنفيذ الأسلوب المجرد بواسطة الفئات المشتقة" )class Dog ( Pet ): def __init__ ( self , name : str ) -> None : super .__ init__ ( name )def speak ( self ) - > None : print ( f " { self.name } says 'Woof!' " )class Cat ( Pet ): def __init__ ( self , name : str ) -> None : super .__ init__ ( name )def speak ( self ) - > None : print ( f " { self.name } says 'Meow!' " )def speak ( pet : Pet ) -> None : # يستدعي دالة speak ديناميكيًا # يمكن أن يكون pet إما نسخة من Dog أو Cat pet.speak ( )إذا كان __name__ يساوي "__main__" : fido : Dog = Dog ( "Fido" ) speak ( fido ) simba : Cat = Cat ( "Simba" ) speak ( simba )

الصدأ

سمة حيوان أليف { دالة التحدث ( & الذات ); }struct Dog <' a > { name : & ' a str }struct Cat <' a > { name : & ' a str }impl <' a > Dog <' a > { fn new ( name : & ' a str ) -> Self { Dog { name } } }impl <' a > Cat <' a > { fn new ( name : & ' a str ) -> Self { Cat { name } } }impl Pet <' a > for Dog < ' a > { fn speak ( & self ) { println! ( "{} says 'Woof!'" , self.name ) ; } }impl Pet <' a > for Cat <' a > { fn speak ( & self ) { println! ( "{} يقول 'مياو!' " , self.name ) ; } }// تستخدم الدالة speak() الإرسال الديناميكي وتُحدد النوع في وقت التشغيل، // لأي نوع يُنفذ السمة Pet fn speak ( pet : & dyn Pet ) { pet . speak (); }fn main () { let fido : Dog = Dog :: new ( "Fido" ); let simba : Cat = Cat :: new ( "Simba" ); speak ( & fido ); speak ( & simba ); }

انظر أيضاً

مراجع

  1. ميلتون، سكوت؛ شميدت، هاينز دبليو. (1994). الإرسال الديناميكي في لغات البرمجة الكائنية (تقرير فني). المجلد  TR-CS-94-02. الجامعة الوطنية الأسترالية. CiteSeerX 10.1.1.33.4292 . 
  2. دريسن، كاريل؛ هولزلي، أورس؛ فيتيك، يان (1995). "إرسال الرسائل على المعالجات ذات خطوط الأنابيب". ECOOP'95 - البرمجة الكائنية التوجه، المؤتمر الأوروبي التاسع، آرهوس، الدنمارك، 7-11 أغسطس 1995. سلسلة محاضرات في علوم الحاسوب. المجلد 952. سبرينغر. CiteSeerX 10.1.1.122.281 . doi : 10.1007/3-540-49538-X_13 . ISBN   3-540-49538-X.
  3. كلابنيك، ستيف؛ نيكولز، كارول (2023) [2018]. "17. ميزات البرمجة كائنية التوجه". لغة برمجة رست ( الطبعة الثانية). سان فرانسيسكو، كاليفورنيا، الولايات المتحدة الأمريكية: دار نشر نو ستارش، الصفحات 375-396 [379-384]. ISBN   978-1-7185-0310-6ص  384: كائنات السمات تُنفذ الإرسال الديناميكي [...] عند استخدام كائنات السمات، يجب على لغة Rust استخدام الإرسال الديناميكي. لا يعرف المُصرّف جميع الأنواع التي قد تُستخدم مع الكود الذي يستخدم كائنات السمات، لذا فهو لا يعرف أي دالة مُنفذة على أي نوع يجب استدعاؤها. بدلاً من ذلك، في وقت التشغيل، تستخدم Rust المؤشرات داخل كائن السمة لمعرفة أي دالة يجب استدعاؤها. يُكبّد هذا البحث تكلفة وقت التشغيل التي لا تحدث مع الإرسال الثابت. كما يمنع الإرسال الديناميكي المُصرّف من اختيار تضمين كود الدالة، مما يمنع بدوره بعض التحسينات.(xxix+1+527+3 صفحات)
  4. "كائنات السمات" . مرجع Rust . تم الاسترجاع في 27-04-2023 .
  5. مولر، مارتن (1995). إرسال الرسائل في لغات البرمجة الكائنية ذات الكتابة الديناميكية (رسالة ماجستير). جامعة نيو مكسيكو. ص 16-17 . CiteSeerX 10.1.1.55.1782 .  

للمزيد من القراءة

  • ليبمان، ستانلي ب. (1996). داخل نموذج كائنات لغة C++ . أديسون-ويسلي . ISBN 0-201-83454-5.
  • جروبر، ماركوس؛ دي جيرونيمو الابن، إدوارد "إد"؛ بول، ماتياس ر. (2002-03-02) [2002-02-24]. "معلومات GEOS/NDO لـ RBIL62؟" . مجموعة الأخبار : comp.os.geos.programmer . تم الاسترجاع في 2019-04-20 . [...] السبب وراء حاجة Geos إلى 16 مقاطعة هو استخدام هذه الآلية لتحويل استدعاءات الدوال بين القطاعات ("البعيدة") إلى مقاطعات، دون تغيير حجم الكود. والسبب في ذلك هو تمكين "شيء ما" (النواة) من ربط نفسه بكل استدعاء بين القطاعات يُجريه تطبيق Geos، والتأكد من تحميل قطاعات الكود المناسبة من الذاكرة الافتراضية وتثبيتها. في مصطلحات DOS ، يُمكن تشبيه ذلك بمُحمِّل تراكبي ، ولكن يُمكن إضافته دون الحاجة إلى دعم صريح من المُصرِّف أو التطبيق. ما يحدث هو كالتالي: […] 1. يُولّد مُصرّف الوضع الحقيقي تعليمةً كهذه: CALL <segment>:<offset> -> 9A <offlow><offhigh><seglow><seghigh>، حيث يُعرَّف <seglow><seghigh> عادةً كعنوان يجب تعديله عند التحميل بناءً على عنوان موضع الكود. […] 2. يُحوّل رابط Geos هذه التعليمة إلى شيء آخر: INT 8xh -> CD 8x […] DB <seghigh>,<offlow>,<offhigh> […] لاحظ أن هذا يتكون من خمسة بايتات، لذا يُمكن تعديله "في مكانه". تكمن المشكلة الآن في أن المقاطعة تتطلب بايتين، بينما تحتاج تعليمة CALL FAR إلى بايت واحد فقط. ونتيجةً لذلك، يجب ضغط متجه 32 بت (<seg><ofs>) إلى 24 بت. […] يتحقق ذلك من خلال أمرين: أولًا، يُشفّر عنوان <seg> كـ "مُعرّف" للقطاع، حيث يكون النصف السفلي منه دائمًا صفرًا. هذا يوفر أربعة بتات. بالإضافة إلى ذلك، […] تُوضع البتات الأربعة المتبقية في النصف السفلي من متجه المقاطعة، مما يُنشئ أي قيمة من INT 80h إلى 8Fh. […] معالج المقاطعة لجميع هذه المتجهات هو نفسه. سيقوم بـ "فك تشفير" العنوان من ترميز الثلاثة بايتات ونصف، والبحث عن العنوان المطلق للقطاع، وإعادة توجيه الاستدعاء، بعد إتمام عملية تحميل الذاكرة الافتراضية... كما ستمر العودة من الاستدعاء عبر رمز إلغاء القفل المُناسب. […] يحتوي النصف السفلي من متجه المقاطعة (80h–8Fh) على البتات من 4 إلى 7 من مُعرّف القطاع. تكون البتات من 0 إلى 3 في مُعرِّف المقطع (بحسب تعريف مُعرِّف Geos) دائمًا صفرًا. [...] تعمل جميع واجهات برمجة تطبيقات Geos من خلال آلية "التراكب" [...]: عند تحميل تطبيق Geos في الذاكرة، يقوم المُحمِّل تلقائيًا باستبدال استدعاءات الدوال في مكتبات النظام بالاستدعاءات المقابلة القائمة على الأعداد الصحيحة. على أي حال، هذه الاستدعاءات ليست ثابتة، بل تعتمد على المُعرِّف المُخصَّص لمقطع التعليمات البرمجية الخاص بالمكتبة.كان من المفترض في الأصل تحويل Geos إلى الوضع المحمي في وقت مبكر جدًا [...]، مع الوضع الحقيقي كونه مجرد "خيار قديم" [...] فإن كل سطر تقريبًا من كود التجميع جاهز له [...]{{cite newsgroup}}: CS1 maint: deprecated archiveal service ( link )
  • بول، ماتياس ر. (11 أبريل 2002). "ردًا على: [ fd-dev ] إعلان: CuteMouse 2.0 alpha 1" . freedos-dev . مؤرشف من الأصل في 21 فبراير 2020. تم الاسترجاع في 21 فبراير 2020. [ ...] في حالة وجود مثل هذه المؤشرات المشوهة [...] منذ سنوات عديدة، كنت أنا وأكسل نفكر في طريقة لاستخدام نقطة دخول واحدة في برنامج تشغيل لعدة متجهات مقاطعة (لأن هذا سيوفر لنا مساحة كبيرة لنقاط الدخول المتعددة ورمز بدء التشغيل/الخروج المتطابق تقريبًا في جميعها)، ثم التبديل إلى معالجات المقاطعة المختلفة داخليًا. على سبيل المثال: 1234h:0000h […] 1233h:0010h […] 1232h:0020h […] 1231h:0030h […] 1230h:0040h […] تشير جميعها إلى نقطة الدخول نفسها تمامًا. إذا قمت بتوصيل المقاطعة 21h بالعنوان 1234h:0000h، والمقاطعة 2Fh بالعنوان 1233h:0010h، وهكذا، فستمر جميعها عبر نفس "الثغرة"، ولكنك ستظل قادرًا على التمييز بينها والتفرع إلى معالجات مختلفة داخليًا. تخيل نقطة دخول "مضغوطة" في وحدة A20 لتحميل HMA . يعمل هذا طالما لم يبدأ أي برنامج في استخدام عمليات segment:offset المعقدة. […] قارن هذا بالنهج المعاكس المتمثل في وجود نقاط دخول متعددة (ربما حتى دعم بروتوكول مشاركة المقاطعات من IBM )، والذي يستهلك ذاكرة أكبر بكثير إذا قمت بتوصيل العديد من المقاطعات. […] توصلنا إلى نتيجة مفادها أن هذا على الأرجح لن يكون آمناً من الناحية العملية، لأنه لا يمكن الجزم بما إذا كانت برامج التشغيل الأخرى تقوم بتطبيع المؤشرات أو إلغاء تطبيعها، ولأي سبب كان. […](ملاحظة: شيء مشابه لـ " المؤشرات السميكة " خاص بعنونة المقطع: الإزاحة في الوضع الحقيقي من إنتل على معالجات x86 ، يحتوي على مؤشر غير مُنمذج عمدًا إلى نقطة دخول مشتركة للتعليمات البرمجية، بالإضافة إلى بعض المعلومات لتمييز المُستدعين المختلفين في التعليمات البرمجية المشتركة. في حين أنه في نظام مفتوح ، لا يمكن استبعاد تطبيع المؤشرات من قِبل جهات خارجية (في برامج تشغيل أو تطبيقات أخرى) تمامًا على الواجهات العامة ، إلا أنه يمكن استخدام هذه الآلية بأمان على الواجهات الداخلية لتجنب تسلسلات التعليمات البرمجية المُكررة.)
  • برايت، والتر (22 ديسمبر 2009). "أكبر خطأ ارتكبه فريق سي" . ديجيتال مارس . مؤرشف من الأصل بتاريخ 8 يونيو 2022. تم الاطلاع عليه بتاريخ 11 يوليو 2022 .
  • هولدن، دانيال (2015). "مكتبة مؤشرات البيانات" . سيلو: لغة سي عالية المستوى . مؤرشف من الأصل بتاريخ 11 يوليو 2022. تم الاطلاع عليه بتاريخ 11 يوليو 2022 .