web-dev-qa-db-ja.com

戻り値が無視された場合に警告を出す方法は?

関数の戻り値を無視するコード(C++)のすべての場所を確認したいと思います。 gccまたは静的コード分析ツールを使用してそれを行うにはどうすればよいですか?

悪いコード例:

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;
}

その点に注意してください:

  • 関数とその使用法が異なるファイルにある場合でも機能するはずです
  • 無料静的チェックツール
54
Drakosha

GCCの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

これは Linuxカーネル ;で使用されていることがわかります。同じことを行う__must_checkマクロがあります。これを機能させるには、GCC3.4以降が必要なようです。次に、カーネルヘッダーファイルで使用されているマクロを見つけます。

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

私の知る限り、この警告を出すGCCオプションはありません。ただし、特定の機能に関心がある場合は、次の属性でタグを付けることができます。

int fn() __attribute__((warn_unused_result));

これは、fn()の戻り値が使用されなかった場合に警告を出します。警告:私はこの機能を自分で使用したことがありません。

10
anon

この便利なテンプレートを使用して、実行時に実行できます。

エラーコード(HRESULTなど)を返す代わりに、return_code <HRESULT>を返します。これは、値が読み取られずにスコープ外になった場合にアサートします。静的分析ツールではありませんが、それでも便利です。

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;
};
10
JoeG

C++ 17の場合、 [[nodiscard]] 属性があるため、この質問に対する答えが変わります。 [dcl.attr.nodiscard] でカバーされています:

属性トークンnodiscardは、関数宣言のdeclarator-id、またはクラスまたは列挙型の宣言に適用できます。これは、各属性リストに最大1回表示され、属性引数句は存在しません。

そして

[例:

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;
}

Gccとclangの両方で診断を取得します。

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

ここでは、静的アナライザーが最善の策です。ここではCoverityを使用していますが、 無料のツール も使用できます。

迅速で汚いソリューションが必要で、Linuxスタイルのシェルが手元にある場合は、次のような方法を試すことができます。

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

これにより、指定された関数を参照しているが「=」を含まないすべての行が検索されます。多くの誤検知(および場合によっては誤検知)が発生する可能性がありますが、静的アナライザーがない場合は、開始するのに適した場所です。

4
bta

静的分析コード(例: PC-Lint )は、それを伝えることができるはずです。 PC-Lintの場合、これが当てはまることを私は知っています。

4
Xavier Nodet

静的アナライザーがあなたに代わって作業を行いますが、コードベースが些細なものである場合は、圧倒される準備をしてください;-)

4
Alon

従来の「lint」プログラムは、無視された値を返す関数について非常に不安定でした。問題は、これらの警告の多くが望ましくないことでした-糸くずの出力に過度のノイズが発生しました(無視したい綿毛を拾っていました)。おそらく、GCCに標準の警告がないのはそのためです。

もう1つの問題(裏側)は、「結果を無視していることがわかっているが、実際には気にしない場合に、警告をどのように抑制するか」です。そのための典型的なシナリオは次のとおりです。

_if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    signal(SIGHUP, sighandler);
_

signal()からの最初の結果が気になります。 2番目がSIG_IGNになることを知っています(これに設定しただけなので)。警告から逃れるために、私は時々いくつかの変形を使用します:

_if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
    old = signal(SIGHUP, sighandler);
_

これにより、両方の時間でoldに割り当てられます。 'assert(old == SIG_IGN)'でそれに従うことができます。

2