الترقيات الوسيطة الافتراضية في مكالمات وظيفة C

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

سؤال

اقامة

لدي بعض الأسئلة حول الترقيات الوسيطة الافتراضية عند الاتصال بوظيفة في C. فيما يلي القسم 6.5.2.2 "وظيفة الدالة" الفقرات 6 و 7 و 8 من C99 Standard (PDF) (أضاف التركيز وكسر إلى قوائم لسهولة القراءة):

الفقرة 6.

  1. إذا كان التعبير الذي يدل على الوظيفة المسمى له نوع لا يشمل النموذج الأولي, ، يتم تنفيذ الترقيات العددية في كل حجة، والحجج التي لديها نوع float يتم ترقيته إلى double. وبعد هذه تسمى الترقيات الوسيطة الافتراضية.
  2. إذا كان عدد الوسيطات لا يساوي عدد المعلمات، فإن السلوك غير محدد.
  3. إذا تم تعريف الوظيفة بنوع ذلك يتضمن نموذجا أوليا, ، وإما النموذج الأولي ينتهي مع علامة القطع (, ...) أو أنواع الحجج بعد الترويج غير متوافقة مع أنواع المعلمات، والسلوك غير محدد.
  4. إذا تم تعريف الوظيفة بنوع ذلك لا يشمل النموذج الأولي, ، وأنواع الحجج بعد الترويج غير متوافقة مع تلك المعلمات بعد الترويج، والسلوك غير محدد، باستثناء الحالات التالية:
    • نوع واحد ترويج هو نوع صحيح موقعة، والنوع الآخر الترويج هو نوع عدد صحيح غير موقعة المقابلة، والقيمة تمثيلية في كلا النوعين؛
    • كلا النوعين مؤشرين للإصدارات المؤهلة أو غير المؤهلة من نوع حرف أو void.

الفقرة 7.

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

الفقرة 8.

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

ما أعرفه

  • ال الترقيات الوسيطة الافتراضية نكون char و short ل int/unsigned int و float ل double
  • الحجج الاختيارية لوظائف المتغيرات (مثل printf) عرضة للترقيات الوسيطة الافتراضية

للسجل، فهمي ل النموذج الأولي وظيفة هذا هو:

void func(int a, char b, float c);  // Function prototype
void func(int a, char b, float c) { /* ... */ }  // Function definition

سؤال

أواجه وقتا صعبا حقا يطئ كل هذا. فيما يلي بعض الأسئلة لدي:

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

المحلول

إجابة Aprogrammer upvoted - تلك هي السلع الحقيقية.

لأولئك منكم الذين يتساءلون لماذا الأشياء بهذه الطريقة: في العصور المظلمة قبل عام 1988، لم يكن هناك شيء مثل النموذج الأولي وظيفة في الكلاسيكية "K & R" C، وتم وضع ترقيات الوسيطة الافتراضية لأن (أ) كان هناك أساسا "مجاني"، لأنه لا يكلف أكثر لوضع بايت في سجل من وضع كلمة في سجل، (ب) خفض الأخطاء المحتملة في المعلمة تمر. هذا السبب الثاني لم يقطعه أبدا، وهذا هو السبب في أن إدخال نماذج النماذج الأولية في ANSI C كان التغيير الوحيد الأكثر أهمية في لغة C.

فيما يتعلق عندما تنطلق العروض الترويجية الافتراضية: يتم استخدام الترقيات الوسيطة الافتراضية بالضبط عندما يكون النوع المتوقع من الوسيطة مجهول, وهو القول عندما لا يوجد نموذج أولي أو عندما تكون الوسيطة المتغيرات.

نصائح أخرى

  • (غير المتغيرات) معلمات الوظائف مع النموذج الأولي يتم تحويلها إلى النوع المقابل، والتي يمكن أن تكون سحر، قصيرة، تعويم.

  • تخضع المعلمات إلى الوظائف دون النموذج الأولي ومعلمات المتغيرات للترقيات الوسيطة الافتراضية.

إذا قمت بتعريف وظيفة مع نموذج أولي واستخدامه دون النموذج الأولي أو ملزمة بالعكس، فإنه يحتوي على معلمات من نوع Char أو Short أو Float، فربما يكون لديك مشكلة في وقت التشغيل. سيكون لديك نفس النوع من المشاكل في وظائف المتغيرات إذا كان النوع المعزز لا يتطابق مع ما يتم استخدامه عند قراءة قائمة الوساطة.

مثال 1: مشكلة عند تحديد وظيفة باستخدام نموذج أولي دون.

تعريف

void f(char c)
{
   printf("%c", c);
}

use.c.

void f();

int main()
{
   f('x');
}

يمكن أن تفشل لأنه سيتم تمرير INT ويتوقع الوظيفة سحر.

مثال 2: المشكلة عند تحديد وظيفة دون نموذج أولي باستخدامها مع واحد.

تعريف

void f(c)
   char c;
{
   printf("%c", c);
}

(هذا هو نوع التعريف أمر قديم جدا)

use.c.

void f(char c);

int main()
{
   f('x');
}

يمكن أن تفشل لأنه من المتوقع ان كثافة دولية ولكن سيتم تمرير أحد.

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

انطلاق الارتباك الخاص بك من سوء فهم خفيف للغاية من المصطلحات - يمكن أن تشمل كل من التصريح والتعاريف النماذج الأولية (أم لا):

void func(int a, char b, float c);

هذه هي وظيفة إعلان يتضمن النموذج الأولي.

void func(int a, char b, float c) { /* ... */ }

هذه هي وظيفة تعريف يتضمن النموذج الأولي.

"النماذج الأولية" و "غير النماذج الأولية" هي مجرد سمات وظيفة اكتب, وكلا التصريحين والتعاريفين يقدمون نوع الوظيفة.

لذلك يمكنك الحصول على إعلان بدون نموذج أولي:

void func();

أو يمكنك الحصول على تعريف بدون أسلوب نموذج (K & R C):

void func(a, b, c)
    int a;
    char b;
    float c;
{ /* ... */ }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top