هل هناك سبب لعدم دعم C99 التحميل الزائد للوظيفة؟

StackOverflow https://stackoverflow.com/questions/1314613

  •  19-09-2019
  •  | 
  •  

سؤال

على ما يبدو (على الأقل وفقا ل gcc -std=c99) C99 لا يدعم التحميل الزائد للوظيفة.عادةً ما يكون سبب عدم دعم بعض الميزات الجديدة في لغة C هو التوافق مع الإصدارات السابقة، لكن في هذه الحالة لا أستطيع التفكير في حالة واحدة يؤدي فيها التحميل الزائد للوظيفة إلى تعطيل التوافق مع الإصدارات السابقة.ما هو السبب وراء عدم تضمين هذه الميزة الأساسية؟

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

المحلول

لفهم سبب عدم احتمالية رؤية التحميل الزائد في لغة C، قد يكون من المفيد معرفة كيفية التعامل مع التحميل الزائد في لغة C++ بشكل أفضل.

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

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

في لغة C، تصبح الوظائف هي أسماء الرموز للرابط، وذلك عند الكتابة

int main(int argc, char **argv) { return 1; }

يوفر المترجم أرشيفًا لرمز الكائن، والذي يحتوي على كائن يسمى main.

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

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

الجانب السلبي لهذا هو أن أسماء الرموز لا تشبه أسماء الوظائف الأصلية.على وجه الخصوص، يكاد يكون من المستحيل التنبؤ باسم الوظيفة المحملة بشكل زائد بحيث يمكنك الارتباط بها.للارتباط بالرمز الأجنبي، يمكنك استخدام extern "C", ، مما يجعل هذه الوظائف تتبع النمط C لأسماء الرموز، ولكن بالطبع لا يمكنك زيادة تحميل هذه الوظيفة.

ترتبط هذه الاختلافات بأهداف التصميم لكل لغة.لغة C موجهة نحو قابلية النقل وقابلية التشغيل البيني.يبذل C قصارى جهده للقيام بأشياء يمكن التنبؤ بها ومتوافقة.لغة C++ موجهة بقوة نحو بناء أنظمة غنية وقوية، ولا تركز بشكل كبير على التفاعل مع اللغات الأخرى.

أعتقد أنه من غير المرجح أن تسعى لغة C إلى متابعة أي ميزة من شأنها إنتاج تعليمات برمجية يصعب التفاعل معها مثل لغة C++.

يحرر: متخيل يسأل:

هل سيكون من الصعب في الحقيقة أو أكثر صعوبة في التفاعل مع وظيفة إذا قمت بحل int main (int argc ، char ** argv) إلى شيء مثل in-in-char ** بدلاً من أن يكون رئيسيًا (وكان هذا جزءًا من المعيار)؟لا أرى مشكلة هنا.في الحقيقة يبدو لي أن هذا يعطيك مزيد من المعلومات (التي يمكن استخدامها للتحسين وما شابه)

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

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

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

في الوقت نفسه، من الممارسات القياسية عمليًا تحديد العديد من وظائف C ذات الأسماء المتشابهة والتي تختلف فقط حسب الأنواع التي تتخذها كوسيطات.للحصول على مثال مطول لهذا فقط، قم بإلقاء نظرة على مساحة الاسم OpenGL.

نصائح أخرى

عند ترجمة المصدر C، ستبقى أسماء الرموز سليمة. إذا قمت بإدخال التحميل الزائد الوظيفي، فيجب عليك تقديم تقنية مشحونة اسم لمنع اشتباكات الاسم. وبالتالي، مثل C ++، سيكون لديك أسماء الرموز التي تم إنشاؤها الجهاز في الثنائي المجمعة.

أيضا، C لا يتميز بالطباعة الصارمة. العديد من الأشياء قابلة للتحويل ضمنيا لبعضها البعض في C. يمكن أن تعقد تعقيد قواعد حل الزائد من التشويش في مثل هذا النوع من اللغة.

تعتقد الكثير من المصممين اللغوي، بما في ذلك، أن مزيج من الوظائف الزائد مع الترويجات الضمنية التي يمكن أن يؤدي إلى التعليمات البرمجية التي يصعب فهمها بشدة. للحصول على أدلة، انظر إلى مجموعة المعرفة المتراكمة حول C ++.

بشكل عام، كان المقصود C99 أن تكون مراجعة متواضعة متوافقة إلى حد كبير مع الممارسة الحالية. الحمولة الزائدة كانت رحيل كبير جدا.

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