int fn();
void whatever()
{
(void) fn();
}
将未使用的返回值强制转换为void是否有任何理由,还是我认为这完全是浪费时间?
David的答案已经涵盖了这一做法的动机,即明确向其他“开发人员”展示你知道该函数有返回值,但你明确忽略了它。
这是一种确保必要的错误代码始终得到处理的方法。
我认为对于C++来说,这可能是我唯一喜欢使用C风格强制类型转换的地方,因为在此处使用完整的静态转换符号感觉就像是过度设计。最后,如果您正在审查编码标准或撰写编码标准,则还应明确说明调用重载运算符(不使用函数调用符号)也应从中豁免:
class A {};
A operator+(A const &, A const &);
int main () {
A a;
a + a; // Not a problem
(void)operator+(a,a); // Using function call notation - so add the cast.
在工作中,我们使用该技巧来承认函数具有返回值,但是开发人员已经断言可以安全地忽略它。由于您将问题标记为C ++,所以您应该使用 static_cast :
static_cast<void>(fn());
就编译器而言,将返回值转换为void几乎没有意义。
__attribute__((warn_unused_result))
,默认情况下警告在C89之前被删除,因此该操作仅适用于非常旧的代码。 - Steve-o这样做的真正原因可以追溯到用于C代码的工具,称为lint。
它分析代码以寻找可能的问题并发出警告和建议。如果一个函数返回一个值,但没有检查该值,lint
会警告是否是意外的。为了消除这个警告,你需要将函数调用转换为(void)
类型。
强制转换为 void
用于抑制编译器警告,提示未使用的变量和未保存的返回值或表达式。
标准(2003) 在 §5.2.9/4 中指出:
任何表达式都可以明确地转换为“cv void”类型,表达式的值被丢弃。
因此,您可以编写以下代码:
//suppressing unused variable warnings
static_cast<void>(unusedVar);
static_cast<const void>(unusedVar);
static_cast<volatile void>(unusedVar);
//suppressing return value warnings
static_cast<void>(fn());
static_cast<const void>(fn());
static_cast<volatile void>(fn());
//suppressing unsaved expressions
static_cast<void>(a + b * 10);
static_cast<const void>( x &&y || z);
static_cast<volatile void>( m | n + fn());
所有表单都是有效的。通常我会将其缩短为:
//suppressing expressions
(void)(unusedVar);
(void)(fn());
(void)(x &&y || z);
这也没问题。
从C++11开始,您还可以这样做:
std::ignore = fn();
在标记了[[nodiscard]]
的函数上,这应该可以实现相同的结果。
[[maybe_unused]]
属性,可以代替void
转换。nodiscard
,可能会引起兴趣:https://dev59.com/0XRB5IYBdhLWcg3wNk53#61675726。另外,我认为你不能直接将 [[maybe_unused]]
应用于调用本身,只能应用于接受调用返回值的虚拟变量?如果这是正确的,那就有点奇怪了。 - Ciro Santilli OurBigBook.com将其转换为void类型是无成本的。这只是告诉编译器如何处理它的信息。
(void)
会浪费我的时间和精力,并让我怀疑作者是否知道表达式的工作原理。 - wallyk对于您程序的功能而言,将其转换为void是没有意义的。我还会认为,不应该像David的答案中建议的那样使用它来向阅读代码的人传递信号。如果您想要传达有关您意图的信息,最好使用注释。添加这样的转换只会看起来奇怪,并引发可能原因的问题。仅代表个人观点...
C++17 [[nodiscard]]
C++17标准化了“返回值被忽略”的问题,并引入了一个属性。
因此,我希望符合规范的实现只会在使用nodiscard
时发出警告,而不会在其他情况下发出警告。
示例:
main.cpp
[[nodiscard]] int f() {
return 1;
}
int main() {
f();
}
编译:
g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -o main.out main.cpp
结果:
main.cpp: In function ‘int main()’:
main.cpp:6:6: warning: ignoring return value of ‘int f()’, declared with attribute nodiscard [-Wunused-result]
6 | f();
| ~^~
main.cpp:1:19: note: declared here
1 | [[nodiscard]] int f() {
|
(void)f();
[[maybe_unused]] int i = f();
我无法直接在f()
调用上使用maybe_unused
:
[[maybe_unused]] f();
提供:
main.cpp: In function ‘int main()’:
main.cpp:6:5: warning: attributes at the beginning of statement are ignored [-Wattributes]
6 | [[maybe_unused]] f();
| ^~~~~~~~~~~~~~~~
(void)
强制转换似乎不是强制性的,但在标准中“鼓励”使用:如何有意地丢弃 [[nodiscard]] 返回值?
此外,从警告消息中可以看出,解决警告的“方法”之一是添加 -Wno-unused-result
:
g++ -std=c++17 -ggdb3 -O0 -Wall -Wextra -pedantic -Wno-unused-result -o main.out main.cpp
虽然我当然不建议像这样全局忽略警告。
C++20还允许您添加一个原因到nodiscard
中,如[[nodiscard("reason")]]
所述:https://en.cppreference.com/w/cpp/language/attributes/nodiscard
GCC warn_unused_result
属性
在[[nodiscard]]
标准化之前,以及在C语言最终决定标准化属性之前,GCC使用warn_unused_result
实现了完全相同的功能:
int f() __attribute__ ((warn_unused_result));
int f() {
return 1;
}
int main() {
f();
}
这将会给出:
main.cpp: In function ‘int main()’:
main.cpp:8:6: warning: ignoring return value of ‘int f()’, declared with attribute warn_unused_result [-Wunused-result]
8 | f();
| ~^~
需要注意的是,由于ANSI C没有针对此进行标准化,因此ANSI C并未指定哪些C标准库函数具有属性,因此实现者已经就应该或不应该用warn_unused_result
做出了自己的决策。一般情况下,您将必须使用(void)
转换来忽略任何对标准库函数的调用返回,以完全避免在任何实现中产生警告。
在GCC 9.2.1,Ubuntu 19.10中进行了测试。
[[maybe_unused]] void f([[maybe_unused]] bool thing1, [[maybe_unused]] bool thing2) { [[maybe_unused]] bool b = thing1 && thing2; assert(b); }
,在你的回答中提到这一点也是有好处的,不是吗? - albertf();
调用意味着什么? - Ciro Santilli OurBigBook.com[[nodiscard]]int f(){...}
时,在调用时不需要返回值,必须使用(void)f();
或static_cast<void>f();
。当使用[[maybe-unused]]f(){...}
时,可以使用f();
。因此,我认为为了完整起见,提及这种可能性(带有示例)是一件好事。当然,所使用的风格取决于用户包在其编码规则/偏好中采用的风格。 - albert