49

最近,我开始使用 lint 进行静态代码分析。我有时收到的警告之一是关于这个问题。例如,假设我有以下功能:

uint32_t foo( void );

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

(void) foo();

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

当我查看这样的代码(带有 void )时,我觉得它看起来很奇怪......

4

10 回答 10

70

常见的方法是直接调用foo();而不转换为(void).

从来不忽略printf()' 的返回值的人,是第一块石头。

于 2012-08-09T17:24:31.253 回答
33

I personally like the "unused" warnings, but on occasion there are instances where I have to ignore them (e.g., the write() to user, or fscanf(...,"%*s\n") or strtol() where the return value is unimportant and I just want the side effect of [maybe] moving the file pointer along.)

With gcc 4.6, it's getting quite tricky.

  • Casting to (void) no longer works.
  • Re-writing functions (especially variadic) is tedious and clumsy.
  • {ssize_t ignore; ignore=write(...);} throws up another warning (assigned-not-used).
  • write(...)+1 throws up yet another warning (computed-value-not-used).

The only good (if ugly) way to suppress these is to convert the return value into something that the compiler agrees that you can ignore.

E.g., (void)(write(...)+1).

This is apparently progress. (And +0 does not work, BTW.)

于 2012-12-22T02:11:11.193 回答
22

使用 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,以便可以在代码的其他地方触发警告。以后阅读您的源代码的任何人都应该更容易看到此代码块的作用。popignored

于 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, ...)

不那么好的演员发生的地方。由于可变参数,在这种情况下使用预处理器宏可能更实用......

于 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如果你这样做,那就是一个解决方案)。

我曾经(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==((long)M)){;}

并这样称呼它:

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

它看起来很干净,任何编译器都会消除代码。下面是我喜欢的编辑器的图片vi:左窗口,没有igr();中间窗口,使用igr(); 右侧窗口,来源。

在此处输入图像描述

你可以看到,它完全一样,一个完全无害的代码让 C 做 gcc 不允许做的事情:忽略返回码。

比较1==...是必要的,只是为了避免这个条件为 no 的夹板警告BOOL。GCC 不在乎。根据功能,您可能会收到cast警告。我用这个 MACRO 做了一个忽略 a 的测试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;
}

不愉快的部分是您需要在某处带有注释的系统函数中添加一个额外的原型。

顺便说一句,默认情况下,Splint不会抱怨printf未使用的其他一些 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 回答