最近,我开始使用lint进行静态代码分析。 我有时得到的一个警告就是这个问题。 比方说,我有以下功能:
uint32_t foo( void );
让我们说我故意忽略函数的返回值。 为了使警告消失,可以写
(void) foo();
我的问题是,编写这样的代码的“正确”方法是什么,我应该像往常一样继续,因为编译器不会抱怨它,或者为了清晰起见我应该使用void,所以其他代码维护者会知道我故意忽略了返回值。
当我看到这样的代码(带有空白)时,对我来说看起来很奇怪......
答案 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()
;右窗口,来源。
你可以看到,它完全相同,是一个完全无害的代码,让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
答案 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;
}