int fn();
void whatever()
{
(void) fn();
}
是否有任何理由将未使用的返回值强制转换为 void,或者我认为这完全是浪费时间?
David 的 answer 几乎涵盖了这样做的动机,明确向其他“开发人员”表明您知道此函数返回,但您明确忽略它。
这是一种确保始终处理必要的错误代码的方法。
我认为对于 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 而言,没有什么意义。
这样做的真正原因可以追溯到 C 代码上使用的工具,称为 lint。
它分析代码寻找可能的问题并发出警告和建议。如果函数返回的值未被检查,
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);
也还可以。
[[maybe_unused]] auto unused = fn();
更新:不建议使用此方法,因为它可能会在规范的未来版本中出现问题。请参阅这篇文章了解更多讨论。
从 C++11 开始,你还可以这样做:
std::ignore = fn();
这应该在标有
[[nodiscard]]
的函数上获得相同的结果
从 c++17 开始,我们有了
[[maybe_unused]]
属性,可以使用它来代替 void
转换。
施放至虚空是无成本的。它只是编译器如何处理它的信息。
对于你的程序功能来说,强制转换为 void 是没有意义的。我还认为,正如大卫的回答所建议的那样,您不应该使用它来向正在阅读代码的人发出某些信号。如果您想传达您的意图,最好使用评论。添加这样的演员表只会看起来很奇怪,并会引发对其可能原因的疑问。只是我的意见...
C++17
[[nodiscard]]
C++17用一个属性规范了“返回值忽略的业务”。
因此,我希望合规的实现始终仅在给出
nodiscard
时发出警告,否则永远不会发出警告。
示例:
主.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();
我无法直接在
maybe_unused
通话中使用 f()
:
[[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_unuesd_result
,这就是为什么通常您必须使用 (void)
强制转换来忽略对标准库函数的任何调用的返回,以完全避免任何实现中的警告。
在 GCC 9.2.1、Ubuntu 19.10 中测试。
此外,在验证您的代码是否符合 MISRA(或其他)标准时,静态分析工具(例如 LDRA)将不允许您调用具有返回类型而不返回值的函数,除非您将返回值显式转换为 (无效)