لماذا تتدفق قبالة نهاية غير وظيفة الفراغ دون إرجاع قيمة لا تنتج مترجم الخطأ ؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

منذ أن أدركت منذ سنوات عديدة ، أن هذا لا ينتج خطأ افتراضي (في دول مجلس التعاون الخليجي على الأقل), لقد تساءلت دائما لماذا ؟

أنا أفهم أن يمكنك إصدار مترجم أعلام لإنتاج تحذير, ولكن لا ينبغي أن يكون دائما خطأ ؟ لماذا لا يعقل غير وظيفة الفراغ لا إرجاع قيمة أن تكون صالحة ؟

مثال على النحو المطلوب في التعليقات:

#include <stdio.h>
int stringSize()
{
}

int main()
{
    char cstring[5];
    printf( "the last char is: %c\n", cstring[stringSize()-1] ); 
    return 0;
}

...برمجيا.

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

المحلول

C99 و C++ المعايير لا تتطلب الدالات بإرجاع قيمة.المفقودين العودة البيان في القيمة العودة وظيفة سيتم تحديد (العودة 0) فقط في main وظيفة.

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

من C++11 مشروع:

§ 6.6.3/2

تتدفق قبالة نهاية دالة [...] نتائج في السلوك غير معرف في القيمة العودة وظيفة.

§ 3.6.1/5

إذا كان التحكم يصل إلى نهاية main من دون مواجهة return بيان تأثير ذلك تنفيذ

return 0;

علما بأن السلوك المبين في C++ 6.6.3/2 ليس هو نفسه في C.


دول مجلس التعاون الخليجي سوف تعطيك تحذير إذا كنت الاتصال مع -Wreturn نوع الخيار.

-Wreturn من نوع تحذير عندما يتم تعريف الدالة بإرجاع نوع التخلف إلى int.يحذر أيضا عن أي بيان عودة بلا عودة القيمة في وظيفة عودتهم من نوع غير الفراغ (السقوط نهاية وظيفة الجسم يعتبر عودته بدون قيمة) ، عن العودة البيان مع تعبير في وظيفة عودتهم من نوع هو باطل.

هذا التحذير هو تمكين -الجدار.


مجرد فضول ، أنظر ما هذا الرمز:

#include <iostream>

int foo() {
   int a = 5;
   int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

هذا الرمز رسميا غير معروف السلوك والممارسة انها واصفا الاتفاقية و العمارة تعتمد.على واحد بعينه نظام معين واحد مترجم, قيمة الإرجاع هي نتيجة آخر تقييم التعبير ، وتخزينها في eax سجل هذا النظام المعالج.

نصائح أخرى

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

Color getColor(Suit suit) {
    switch (suit) {
        case HEARTS: case DIAMONDS: return RED;
        case SPADES: case CLUBS:    return BLACK;
    }

    // Error, no return?
}

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

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

char getChoice() {
    int ch = read();

    if (ch == -1 || ch == 'q') {
        System.exit(0);
    }
    else {
        return (char) ch;
    }

    // Cannot reach here, but still an error.
}

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

هل تعني، لماذا تتدفق قبالة نهاية وظيفة ذات القيمة العودة (أي الخروج دون return صريح) لا خطأ؟

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

وثانيا، على ما يبدو مواصفات اللغة لا تريد لإجبار الكتاب مترجم للكشف والتحقق من جميع مسارات الرقابة الممكنة لوجود return صريحة (على الرغم من أن في كثير من الحالات وهذا ليس من الصعب القيام به). أيضا، قد تؤدي بعض المسارات تحكم في ل<م> غير العائدين وظائف - سمة التي عادة غير معروفة للمترجم. ويمكن لهذه المسارات تصبح مصدرا من ايجابيات كاذبة مزعج.

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

ومن قانوني بموجب C / C ++ للن يعود من دالة التي تدعي أن يعود شيء. وهناك عدد من حالات الاستخدام، مثل الدعوة exit(-1)، أو الوظيفة التي يسميها أو يطرح استثناء.

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

وتغيير الافتراضي عدم ARG دول مجلس التعاون الخليجي لتنبعث منها بعض التحذيرات يمكن أن يكون تغيير فصل للمخطوطات الموجودة أو جعل النظم. مصممة بشكل جيد منها إما -Wall والتعامل مع التحذيرات، أو تبديل التحذيرات الفردية.

وتعلم استخدام C ++ سلسلة الأداة عائقا أمام تعلم أن تكون مبرمج C ++، ولكن C ++ سلاسل أداة عادة ما تكون مكتوبة من قبل وللخبراء.

وتحت أي ظرف من الظروف أليس كذلك ينتج خطأ؟ اذا اعلنت نوع إرجاع ولا يعود شيء، فإنه يبدو وكأنه خطأ بالنسبة لي.

والاستثناء الوحيد الذي يمكنني أن أفكر من هي وظيفة main()، الذي لا يحتاج إلى بيان return على الإطلاق (على الأقل في C ++، وأنا لم يكن لديك أي من المعايير C يدوية). إذا لم يكن هناك عودة، وسوف تتصرف كما لو return 0; هو البيان الأخير.

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

$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$

وأعتقد أن هذا هو بسبب من التعليمات البرمجية القديمة (بيان عودة C أبدا المطلوبة وكذلك فعل C ++). وربما كان هناك رمز قاعدة ضخمة تعتمد على أن "الميزة". ولكن على الأقل هناك -Werror=return-type العلم على العديد من المجمعين (بما في ذلك دول مجلس التعاون الخليجي ورنة).

وبل هو انتهاك القيد في C99، ولكن ليس في C89. التباين:

وC89:

<اقتباس فقرة>   

و3.6.6.4 البيان return

     

والقيود

     

لا يجوز أن يظهر بيان return مع تعبير في   وظيفة له نوع إرجاع هي void.

وC99:

<اقتباس فقرة>   

و6.8.6.4 البيان return

     

والقيود

     

لا يجوز أن يظهر بيان return مع تعبير في وظيفة الذي هو void نوع الإرجاع. يجب بيان return دون تعبير تظهر فقط في وظيفة الذي هو void نوع الإرجاع.

وحتى في وضع --std=c99، ودول مجلس التعاون الخليجي رمي فقط تحذير (على الرغم من دون الحاجة إلى تمكين الأعلام -W إضافية، كما هو مطلوب من قبل الافتراضي أو في C89 / 90).

وتحرير لإضافة أنه في C89 "، والوصول إلى } أن ينهي وظيفة ما يعادل تنفيذ بيان return دون التعبير "(3.6.6.4). ومع ذلك، في C99 هي غير معرفة سلوك (6.9.1).

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