忽略C中的返回值

时间:2012-08-09 17:15:28

标签: c coding-style return-value lint

最近,我开始使用lint进行静态代码分析。 我有时得到的一个警告就是这个问题。 比方说,我有以下功能:

uint32_t foo( void );

让我们说我故意忽略函数的返回值。 为了使警告消失,可以写

(void) foo();

我的问题是,编写这样的代码的“正确”方法是什么,我应该像往常一样继续,因为编译器不会抱怨它,或者为了清晰起见我应该使用void,所以其他代码维护者会知道我故意忽略了返回值。

当我看到这样的代码(带有空白)时,对我来说看起来很奇怪......

10 个答案:

答案 0 :(得分:53)

常见的方法是只需拨打foo();即可转入(void)

从未忽略printf()的回报值的人,铸造了第一块石头。

答案 1 :(得分:26)

我个人喜欢“未使用”的警告,但偶尔会有我不得不忽略它们的情况(例如write()用户,或fscanf(...,"%*s\n")strtol()返回值并不重要,我只想要[可能]移动文件指针的副作用。)

使用gcc 4.6,它变得非常棘手。

  • 投放到(void)不再有效。
  • 重写函数(尤其是可变函数)是乏味且笨拙的。
  • {ssize_t ignore; ignore=write(...);}会抛出另一个警告(已分配 - 未使用)。
  • write(...)+1引发了另一个警告(计算值未使用)。

抑制这些的唯一好处(如果丑陋)的方法是将返回值转换为编译器同意您可以忽略的内容。

,例如(void)(write(...)+1)

这显然是进步。 (并且+0不起作用,BTW。)

答案 2 :(得分:16)

使用Clang和GCC编译器执行此操作的一种方法是使用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指令,以便可以在代码中的其他位置触发警告。对于那些阅读源代码的人来说,看看这个代码块的作用应该更容易。

答案 3 :(得分:8)

要使静态代码检查器有用,它还应报告忽略的返回值,这可能导致很难跟踪错误 - 或者错过错误处理。

因此,您应该保留(void)或停用对printf的检查。现在,您可以通过多种方式以可读的方式执行此操作。我用来将函数包装在一个新函数中,例如

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

不太好的演员阵容发生在那里。在这种情况下使用预处理器宏可能更实际,因为varargs ......

答案 4 :(得分:8)

稍微多一点"美丽"指示未使用结果的方式是:

/**
 * 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(T /* unused result */) {}

答案 5 :(得分:5)

我喜欢使用标志编译我的代码:

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

为了避免-Wunused-result我不喜欢添加另一个标志:-Wno-unused-result(如果你这样做,那就是一个解决方案)。

我过去常常为(void)强制转换某些函数(不是printf或其他着名的函数,因为编译器不会对它们发出警告,只有奇怪的函数)。现在,转换为(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==((int)M)){;}

并称之为:

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

它外观干净,任何编译器都会消除代码。我的首选编辑vi的图片:左侧窗口,没有igr();中间窗口,使用igr();右窗口,来源。

enter image description here

你可以看到,它完全相同,是一个完全无害的代码,让C做gcc不会让的:忽略返回代码。

比较1==...只是为了避免夹板警告此条件不是BOOL。海湾合作委员会不在乎。根据功能,您可能会收到cast警告。我做了一个测试忽略了double这个MACRO并且它很好,但不知怎的,我不完全相信。特别是如果函数返回指针或更复杂的东西。

在这种情况下,您还需要:

#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

另见this answer

答案 6 :(得分: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

答案 7 :(得分: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;
}

令人不快的是,您需要在系统函数中添加一个额外的原型,并在某处添加注释。

顺便说一句,默认情况下, Splint 不会抱怨printf的返回值以及其他一些未使用的libc函数。但是,可以激活更严格的模式。

LINT允许类似的东西,但我从未使用它。这是文档所说的内容。

  

LINT允许您使用a标记具有可选返回值的函数   指令类似于C预处理器的#directives。

     

#pragma optresult

     

可以放在函数定义之前   返回可选结果。 LINT然后识别出这个功能   返回可以忽略的结果; LINT不会出错   如果忽略结果,则显示消息。

答案 8 :(得分:0)

其他解决方案是实际使用一个值。然后,您可以使用宏删除unused variable警告。

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

然后在你的例子中,你有:

val = foo();
_unused(val); 

答案 9 :(得分:-2)

在某些情况下编写忽略返回值的代码是完全合法且可接受的。下面的程序几乎没有理由检查printf()的返回值。

int main(void) {
  printf("Hello world\n");
  return 0;
}