سؤال

أود أن أرى كل الأماكن في التعليمات البرمجية (C ++) التي تجاهل قيمة الإرجاع لوظيفة. كيف يمكنني القيام بذلك - مع أداة تحليل دول مجلس التعاون الخليجي أو ثابتة رمز؟

مثال رمز سيء:

int f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}


int main()
{
  int i = 7;
  f(i); ///// <<----- here I disregard the return value

  return 1;
}

يرجى ملاحظة أن:

  • يجب أن تعمل حتى لو كانت الوظيفة واستخدامها في ملفات مختلفة
  • مجانا أداة التحقق الثابتة
هل كانت مفيدة؟

المحلول

تريد دول مجلس التعاون الخليجي warn_unused_result ينسب:

#define WARN_UNUSED __attribute__((warn_unused_result))

int WARN_UNUSED f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}

int main()
{
  int i = 7;
  f(i); ///// <<----- here i disregard the return value
  return 1;
}

تحاول ترجمة هذا الرمز ينتج:

$ gcc test.c
test.c: In function `main':
test.c:16: warning: ignoring return value of `f', declared with
attribute warn_unused_result

يمكنك أن ترى هذا قيد الاستخدام في نواة لينكس; ؛ لديهم أ __must_check ماكرو الذي يفعل نفس الشيء؛ يبدو أنك بحاجة إلى دول مجلس التعاون الخليجي 3.4 أو أكبر لهذا العمل. ثم ستجد أن الماكرو المستخدمة في ملفات رأس kernel:

unsigned long __must_check copy_to_user(void __user *to,
                                        const void *from, unsigned long n);

نصائح أخرى

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

int fn() __attribute__((warn_unused_result));

والتي من شأنها أن تعطي تحذيرا إذا لم يتم استخدام قيمة العودة FN (). التحذير: أنا لم أستخدم هذا ميزة نفسي.

يمكنك استخدام هذا القالب المفيد للقيام بذلك في وقت التشغيل.

بدلا من إرجاع رمز الخطأ (على سبيل المثال HRESult)، فإنك ترجع العودة_CODEu003CHRESULT> ، الذي يؤكد إذا خرج من النطاق دون قراءة القيمة. إنها ليست أداة تحليل ثابتة، لكنها مفيدة بلا أقل.

class return_value
{
public:
  explicit return_value(T value)
    :value(value), checked(false)
  {
  }

  return_value(const return_value& other)
    :value(other.value), checked(other.checked)
  {
    other.checked = true;
  }

  return_value& operator=(const return_value& other)
  {
    if( this != &other ) 
    {
      assert(checked);
      value = other.value;
      checked = other.checked;
      other.checked = true;
    }
  }

  ~return_value(const return_value& other)
  {
    assert(checked);
  }

  T get_value()const {
    checked = true;
    return value;
  }

private:
  mutable bool checked;
  T value;
};

ل C ++ 17 الإجابة على تغييرات السؤال هذه لأن لدينا الآن [Nodiscard] ينسب. مغطاة dcl.attr.nodiscard:

قد يتم تطبيق Nodiscard Token-Token على معرف المعلن في إعلان الوظائف أو لإعلان الفصل أو التعداد. يجب أن تظهر مرة واحدة في كل قائمة سمة ولن يكون هناك أي شروط وسيطة للأسف.

و

مثال:

struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
  enable_missile_safety_mode(); // warning encouraged
  launch_missiles();
}
error_info &foo();
void f() { foo(); }             // warning not encouraged: not a nodiscard call, because neither
                                // the (reference) return type nor the function is declared nodiscard

- مثال النهاية

لذلك تعديل مثالك (انظر انه لايف):

[[nodiscard]] int f(int z) {
    return z + (z*2) + z/3 + z*z + 23;
}


int main()
{
  int i = 7;
  f(i); // now we obtain a diagnostic

  return 1;
}

نحصل الآن على تشخيص مع كل من دول مجلس التعاون الخليجي وكلانغ على سبيل المثال

warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
  f(i); // now we obtain a diagnostic
  ^ ~

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

سيقوم محلل ثابت بالعمل من أجلك، ولكن إذا كانت قاعدة الكود الخاصة بك أكثر استعدادا تافهة لتكون غامضة ؛-)

محلل ثابت سيكون أفضل رهان هنا. نحن نستخدم الخيذة هنا، ولكن هناك أدوات مجانية متاح أنه يمكنك استخدامه كذلك.

إذا كنت بحاجة إلى حل سريع وقذر ولديك قذيفة نمط Linux مفيد، يمكنك تجربة شيء مثل:

grep -rn "function_name" * | grep -v "="

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

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

المشكلة الأخرى - الجانب الآخر - هو "كيف تقمع التحذير عندما تعرف أنك تتجاهل النتيجة ولكن لا يهتم حقا". السيناريو الكلاسيكي لهذا هو:

if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    signal(SIGHUP, sighandler);

أنت تهتم النتيجة الأولى من signal(); ؛ أنت تعرف أن الثانية ستكون SIG_IGN (نظرا لأنك فقط ضعها على ذلك). للابتعاد عن التحذيرات، وأحيانا استخدم بعض البديل على:

if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
    old = signal(SIGHUP, sighandler);

هذا يعين إلى old في المرتين. يمكنك اتباع ذلك مع "تأكيد (قديم == Sig_ign)".

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