忽略C中的返回值

忽略C中的返回值,c,coding-style,return-value,lint,C,Coding Style,Return Value,Lint,最近,我开始使用lint进行静态代码分析。 我有时得到的警告之一是关于这个问题。 比如说,我有以下函数: uint32_t foo( void ); 假设我谨慎地忽略了函数的返回值。 要使警告消失,可以写 (void) foo(); 我的问题是,编写这样的代码的“正确”方式是什么,我应该像往常一样继续,因为编译器不会对此抱怨,还是应该使用void来澄清问题,这样其他代码维护者就会知道我故意忽略了返回值 当我看到这样的代码(带有void)时,我觉得很奇怪……在某些情况下,编写忽略返回值的代码是

最近,我开始使用lint进行静态代码分析。 我有时得到的警告之一是关于这个问题。 比如说,我有以下函数:

uint32_t foo( void );
假设我谨慎地忽略了函数的返回值。 要使警告消失,可以写

(void) foo();
我的问题是,编写这样的代码的“正确”方式是什么,我应该像往常一样继续,因为编译器不会对此抱怨,还是应该使用void来澄清问题,这样其他代码维护者就会知道我故意忽略了返回值


当我看到这样的代码(带有void)时,我觉得很奇怪……

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


常用的方法是只调用
foo()未强制转换为
(无效)


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

要使静态代码检查器有用,它还应该报告被忽略的返回值,这通常会导致难以跟踪错误或丢失错误处理

因此,您应该保留
(void)
或取消选中
printf
。现在,您有几个选项可以以可读的方式进行操作。我通常将函数包装在一个新函数中,例如

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

演员阵容不太好的地方。在这种情况下,使用预处理器宏可能更为实际,因为varargs…

通常没有太多的函数需要忽略其值。例如,Splint允许添加一条特殊注释,让它知道特定函数的返回值可能被忽略。不幸的是,这实际上禁用了与该特定函数相关的所有“忽略返回值”警告

以下是夹板清洁程序的示例:

#包括
FILE/*@alt void@*/*fopen(常量字符*路径,常量字符*模式);
静态int/*@alt void@*/test(void)
{
printf(“称为\n的测试”);
fopen(“测试”、“a”);
返回0;
}
内部主(空)
{  
test();
返回0;
}
令人不快的是,您需要在系统函数的某个地方添加一个带有注释的附加原型

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

LINT允许类似的功能,但我从未使用过它。下面是一份文档所说的内容

LINT允许您通过使用 指令类似于C预处理器的#指令

#布拉格光结果

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

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

对于GCC4.6,它变得相当棘手

  • 铸造到
    (无效)
    不再有效
  • 重新编写函数(尤其是可变函数)既繁琐又笨拙
  • {ssize\u t ignore;ignore=write(…);}
    抛出另一个警告(分配的未使用)
  • write(…)+1
    抛出另一个警告(未使用计算值)
抑制这些的唯一好方法(如果不好的话)是将返回值转换为编译器同意您可以忽略的值

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


这显然是进步。(顺便说一句,
+0
不起作用)

使用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
指令,以便可以在代码的其他地方触发警告。阅读源代码的人应该更容易看到此代码块的功能。

指示未使用结果的一种稍微“漂亮”的方法是:

/**
 * 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 */) {}
模板
内联void ignore_result(常量T&/*未使用的结果*/){

我喜欢用以下标志编译代码:

$gcc prog1.c -o prog1.x -Wall -Wextra -ansi -pedantic-errors -g -O0 -DDEBUG=1
为了避免
-Wunused result
我不喜欢添加另一个标志:
-Wno unused result
(如果这样做,这是一个解决方案)

我曾经为一些函数(不是
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需要更新有关此问题的信息

因此,为了以非常兼容的方式消除警告,这里有一个很好的

/** 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==…
仅用于避免夹板警告此条件为no
BOOL
。GCC对此毫不在乎。根据功能的不同,可能会出现
cast
警告。我用这个宏做了一个测试,忽略了一个
double
,结果很好,但是som
/** Turn off -Wunused-result for a specific function call */
#define igr(M) if(1==((int)M)){;}
igr(PL_get_chars(t, &s, CVT_VARIABLE));
#define pigr(M) if(NULL==((void *)M)){;}
$ splint ./teste.c -I/usr/lib/swi-prolog/include/ -strict-lib
Splint 3.1.2 --- 20 Feb 2009

Finished checking --- no warnings
#define _unused(x) ((void)(x))
val = foo();
_unused(val); 
/* 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