49

最近、静的コード分析にlintを使い始めました。私が時々受ける警告の1つは、この問題に関するものです。たとえば、次の関数があるとします。

uint32_t foo( void );

そして、関数の戻り値を故意に無視したとしましょう。警告を消すために、次のように書くことができます

(void) foo();

私の質問は、このようなコードを書くための「適切な」方法は何ですか、コンパイラはそれについて文句を言わないのでいつものように続けるべきですか、それとも明確にするためにボイドを使うべきですか、それで他のコードメンテナは知っています戻り値を故意に無視したこと。

このようなコード(voidを使用)を見ると、かなり奇妙に見えます...

4

10 に答える 10

70

foo();一般的な方法は、にキャストせずに呼び出すこと(void)です。

の戻り値を無視したことがない彼はprintf()、最初の石を投げました。

于 2012-08-09T17:24:31.253 に答える
33

私は個人的に「未使用」の警告が好きですが、場合によってはそれらを無視しなければならない場合があります(たとえば、write()toユーザー、またはfscanf(...,"%*s\n")戻りstrtol()値が重要ではなく、ファイルを移動するという副作用が必要な場合があります)。ポインタに沿って。)

gcc 4.6では、かなり注意が必要です。

  • キャストは(void)機能しなくなりました。
  • 関数の書き換え(特に可変個引数)は退屈で不器用です。
  • {ssize_t ignore; ignore=write(...);}別の警告をスローします(割り当て済み-未使用)。
  • write(...)+1さらに別の警告をスローします(計算値未使用)。

これらを抑制する唯一の良い(醜い場合)方法は、戻り値を、コンパイラが無視できることに同意するものに変換することです。

例:(void)(write(...)+1)

これは明らかに進歩です。(そして、+0動作しません、ところで。)

于 2012-12-22T02:11:11.193 に答える
22

ClangおよびGCCコンパイラでこれを行う1つの方法は、pragma:を使用することです。

    /* ... */

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result" 

    foo(); /* this specific unused-result warning gets ignored during compilation */

#pragma GCC diagnostic pop 

    /* ... */

push-のpop組み合わせは、ディレクティブをラップignoredして、コードの他の場所で警告をトリガーできるようにします。ソースコードを読んでいる人なら誰でも、このコードブロックが何をするのかを簡単に確認できるはずです。

于 2014-11-11T00:12:48.803 に答える
13

未使用の結果を示すもう少し「美しい」方法は次のとおりです。

/**
 * Wrapping your function call with ignore_result makes it more clear to
 * readers, compilers and linters that you are, in fact, ignoring the
 * function's return value on purpose.
 */
static inline void ignore_result(long long int unused_result) {
    (void) unused_result;
}

...

ignore_result(foo());

を使用C++すると、これを次のように拡張できます。

template<typename T>
inline void ignore_result(const T & /* unused result */) {}
于 2015-05-07T11:25:40.387 に答える
9

静的コードチェッカーが役立つためには、無視された戻り値も報告する必要があります。これにより、エラーの追跡が困難になったり、エラー処理が欠落したりすることがよくあります。

したがって(void)、のチェックを保持するか、非アクティブ化する必要がありprintfます。これで、読みやすい方法でそれを行うためのいくつかのオプションがあります。たとえば、関数を新しい関数内にラップするために使用します

void printf_unchecked(const char* format, ...)

あまり良くないキャストが行われる場所。おそらく、この場合、varargsのために、プリプロセッサマクロを使用してそれを行う方が実用的です...

于 2012-08-09T17:28:36.650 に答える
8

フラグを使用してコードをコンパイルするのが好きです。

$gcc prog1.c -o prog1.x -Wall -Wextra -ansi -pedantic-errors -g -O0 -DDEBUG=1

そして、避けるために、-Wunused-result私は別のフラグを追加するという考えが好きではありません:(-Wno-unused-resultもしそうなら、それは1つの解決策です)。

(void)私は以前、いくつかの関数にキャストしていましprintfた(コンパイラーはそれらについて警告しないので、奇妙な関数だけで、他の有名な関数ではありません)。toのキャストが(void)機能しなくなりました(GCC 4.7.2)

面白い副子はアドバイスします:

Result returned by function call is not used. If this is intended,
can cast result to (void) to eliminate message. (Use -retvalother to
inhibit warning)

しかし、これはもはや解決策ではありません。Splintは、この問題に関する更新が必要です。

したがって、非常に互換性のある方法で警告を取り除くために、ここに良いものがありMACROます:

/** Turn off -Wunused-result for a specific function call */
#define igr(M) if(1==((long)M)){;}

そしてそれをこのように呼んでください:

igr(PL_get_chars(t, &s, CVT_VARIABLE));

その見た目はすっきりしていて、どのコンパイラもコードを排除します。私の好みの編集者の写真を下に示してviください:左のウィンドウ、いいえigr(); 中央のウィンドウ、igr();を使用 右ウィンドウ、ソース。

ここに画像の説明を入力してください

まったく同じで、Gccが許可しないことをCに実行させる完全に無害なコードを見ることができます。戻りコードを無視してください。

比較1==...は、この条件がnoであるというスプリント警告を回避するためにのみ必要ですBOOL。GCCはそれほど気にすることはできませんでした。機能によっては、cast警告が表示される場合があります。このマクロを無視してテストをしてdouble良かったのですが、どういうわけか完全には納得できません。特に、関数がポインタまたはより複雑なものを返す場合。

この場合、次のものも必要になります。

#define pigr(M) if(NULL==((void *)M)){;}

最後{;}に、警告のために必要です-Wempty-body('if'ステートメントで空の本体を中括弧で囲むことをお勧めします)。

そして(今最後に);関数呼び出しの後は(厳密に)必要ではありませんが、その良い習慣です。コード行をより均質にし、すべてがで終わるようにし;ます。(ニーモニックとして変換され、NOP最適化後に消えます)。


コンパイラを実行しても、警告やエラーは発生しません。実行splintすると:

$ splint ./teste.c -I/usr/lib/swi-prolog/include/ -strict-lib
Splint 3.1.2 --- 20 Feb 2009

Finished checking --- no warnings

この回答も参照してください

于 2015-06-23T05:02:54.650 に答える
3

gnulibにはこれがあります:http: //git.savannah.gnu.org/cgit/gnulib.git/tree/lib/ignore-value.h

/* Normally casting an expression to void discards its value, but GCC
   versions 3.4 and newer have __attribute__ ((__warn_unused_result__))
   which may cause unwanted diagnostics in that case.  Use __typeof__
   and __extension__ to work around the problem, if the workaround is
   known to be needed.  */
#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__)
# define ignore_value(x) \
    (__extension__ ({ __typeof__ (x) __x = (x); (void) __x; }))
#else
# define ignore_value(x) ((void) (x))
#endif
于 2016-09-21T14:03:52.477 に答える
1

通常、値を無視したい関数はそれほど多くありません。たとえば、Splintを使用すると、特定の関数の戻り値が無視される可能性があることを通知する特別なコメントを追加できます。残念ながら、これは事実上、その特定の関数に関連するすべての「無視された戻り値」警告を無効にします。

Splint-cleanプログラムの例を次に示します。

#include <stdio.h>

FILE /*@alt void@*/ *fopen(const char *path, const char *mode);

static int /*@alt void@*/ test(void)
{
   printf( "test called\n" );

   fopen( "test", "a" );

   return 0;
}

int main(void)
{  
   test();

   return 0;
}

不快な部分は、どこかにコメントを付けてシステム関数にプロトタイプを追加する必要があることです。

ところで、デフォルトでは、Splintprintf、使用されていない他のいくつかのlibc関数の戻り値について文句を言いません。ただし、より厳密なモードをアクティブにすることはできます。

LINTは似たようなものを許可しますが、私はそれを使ったことがありません。これがドキュメントの内容です。

LINTを使用すると、Cプリプロセッサの#directivesと同様のディレクティブを使用して、オプションの戻り値で関数をマークできます。

#pragma optresult

オプションの結果を返す関数の定義の直前に配置できます。次に、LINTは、この関数が無視できる結果を返すことを認識します。結果が無視された場合、LINTはエラーメッセージを表示しません。

于 2012-08-09T17:43:02.103 に答える
1

他の解決策は、実際に値を使用することです。unused variable次に、マクロを使用して警告を削除できます。

#define _unused(x) ((void)(x))

次に、あなたの例では、次のようになります。

val = foo();
_unused(val); 
于 2016-03-21T16:54:25.890 に答える
-1

場合によっては戻り値を無視するコードを書くことは完全に合法であり、受け入れられます。以下のプログラムには、printf()の戻り値をチェックする理由がほとんどありません。

int main(void) {
  printf("Hello world\n");
  return 0;
}
于 2012-08-09T17:20:55.360 に答える