我想看看我的代码(C ++)中忽略函数返回值的所有位置。我怎么能用gcc或静态代码分析工具呢?
错误代码示例:
int f(int z) {
return z + (z*2) + z/3 + z*z + 23;
}
int main()
{
int i = 7;
f(i); ///// <<----- here I disregard the return value
return 1;
}
请注意:
答案 0 :(得分:54)
您需要GCC的warn_unused_result
属性:
#define WARN_UNUSED __attribute__((warn_unused_result))
int WARN_UNUSED f(int z) {
return z + (z*2) + z/3 + z*z + 23;
}
int main()
{
int i = 7;
f(i); ///// <<----- here i disregard the return value
return 1;
}
尝试编译此代码会产生:
$ gcc test.c
test.c: In function `main':
test.c:16: warning: ignoring return value of `f', declared with
attribute warn_unused_result
您可以在Linux kernel中看到这一点;他们有一个__must_check
宏做同样的事情;看起来你需要GCC 3.4或更高版本才能工作。然后你会发现内核头文件中使用的宏:
unsigned long __must_check copy_to_user(void __user *to,
const void *from, unsigned long n);
答案 1 :(得分:10)
据我所知,没有GCC选项可以发出此警告。但是,如果您对特定功能感兴趣,可以使用以下属性标记它们:
int fn() __attribute__((warn_unused_result));
如果未使用fn()的返回值,则会发出警告。警告:我自己从未使用过此功能。
答案 2 :(得分:10)
您可以使用这个方便的模板在运行时执行此操作。
不返回错误代码(例如HRESULT),而是返回一个return_code&lt; HRESULT&gt;,如果超出范围而没有读取值,则返回该断言。它不是一个静态分析工具,但它仍然有用。
class return_value
{
public:
explicit return_value(T value)
:value(value), checked(false)
{
}
return_value(const return_value& other)
:value(other.value), checked(other.checked)
{
other.checked = true;
}
return_value& operator=(const return_value& other)
{
if( this != &other )
{
assert(checked);
value = other.value;
checked = other.checked;
other.checked = true;
}
}
~return_value(const return_value& other)
{
assert(checked);
}
T get_value()const {
checked = true;
return value;
}
private:
mutable bool checked;
T value;
};
答案 3 :(得分:7)
对于C ++ 17,由于我们现在拥有[[nodiscard]]属性,因此该问题的答案有所变化。在[dcl.attr.nodiscard]中涵盖:
可以将attribute-token nodiscard应用于函数声明中的declarator-id或类或枚举的声明。它在每个属性列表中最多出现一次,并且不存在任何属性参数子句。
和
[示例:
struct [[nodiscard]] error_info { /* ... */ }; error_info enable_missile_safety_mode(); void launch_missiles(); void test_missiles() { enable_missile_safety_mode(); // warning encouraged launch_missiles(); } error_info &foo(); void f() { foo(); } // warning not encouraged: not a nodiscard call, because neither // the (reference) return type nor the function is declared nodiscard
-示例]
因此,请修改您的示例(see it live):
[[nodiscard]] int f(int z) {
return z + (z*2) + z/3 + z*z + 23;
}
int main()
{
int i = 7;
f(i); // now we obtain a diagnostic
return 1;
}
我们现在可以通过gcc和clang获得诊断信息。
warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
f(i); // now we obtain a diagnostic
^ ~
答案 4 :(得分:4)
任何静态分析代码(例如PC-Lint)都应该能够告诉您。对于PC-Lint,我知道情况确实如此。
答案 5 :(得分:4)
静态分析器将为您完成这项工作,但如果您的代码库更多,那么准备不堪重负; - )
答案 6 :(得分:4)
静态分析仪将是您最好的选择。我们在这里使用Coverity,但也可以使用free tools。
如果你需要一个快速而肮脏的解决方案并且你有一个方便的Linux风格的外壳,你可以尝试类似的东西:
grep -rn "function_name" * | grep -v "="
这将找到引用指定函数但不包含“=”的每一行。您可能会得到很多误报(可能还有一些误报),但如果您没有静态分析仪,那么它就是一个不错的起点。
答案 7 :(得分:2)
经典的'lint'程序过去常常对返回被忽略的值的函数非常感兴趣。麻烦的是,许多警告是不必要的 - 导致皮棉输出中的噪音过大(它正在捡起你想要忽略的一点点绒毛)。这可能就是GCC没有标准警告的原因。
另一个问题 - 另一方面 - “如果你知道自己忽略了结果但是真的不在意,你怎么压制警告”。经典场景是:
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, sighandler);
你关心signal()
的第一个结果;你知道第二个是SIG_IGN(因为你只是设置它)。为了摆脱这些警告,我有时会使用一些变体:
if ((old = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
old = signal(SIGHUP, sighandler);
这两次分配给old
。您可以使用'assert(old == SIG_IGN)'来跟随它。