为什么将未使用的返回值强制转换为无效?


112
int fn();

void whatever()
{
    (void) fn();
}

是否有任何理由将未使用的返回值转换为空,还是我认为这完全是浪费时间?

跟进:

好吧,这似乎很全面。我想这比注释未使用的返回值要好,因为自我记录代码比注释要好。我个人将关闭这些警告,因为这是不必要的噪音。

如果一个错误因它而逃脱,我会吃我的话。

Answers:


79

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风格演员表的地方。在我的编码标准中,我将(void)添加到“ a + a;” 太(当然,适当地降低了:p)
约翰内斯·绍布

8
有点偏离主题,但是为什么您会做“ a + a;”?这样不使用返回值?在我看来,这确实是对副作用的滥用,并且使代码的意图难以理解。
罗布K

5
好吧,您每天都会使用一个“ a = a”。这将返回分配给对象(对于所有表现良好的类!)。另一个示例是:os <<“ Hello World” << std :: endl。它们每个都返回“ os”对象。
理查德·科登,2009年

46

在工作中,我们使用它来确认该函数具有返回值,但是开发人员断言可以忽略它。由于您将问题标记为C ++,因此应该使用static_cast

static_cast<void>(fn());

就编译器而言,将返回值强制转换为void几乎没有意义。


它是否抑制了有关未使用的返回值的警告?
Paul Tomblin,2009年

不,不是的。@Mykola:使用GCC4,您可以附加一个属性,该属性表示不应忽略返回值,这将触发警告。
David Holm,2009年

2
我使用g ++,即使使用这种强制转换,它也会发出警告。
klew

2
您使用哪个警告选项?-物有所值的值不会在我的环境中触发警告
Mykola Golubyev 2009年

在VC ++中,它禁止显示警告
杰夫(Jalf)2009年

39

这样做的真正原因可以追溯到C代码上使用的称为lint的工具。

它分析代码以查找可能的问题并发出警告和建议。如果函数返回的值随后未被检查,lint则会发出警告,以防万一。要使lint此警告静音,您可以将呼叫投射到(void)


2
它可能以这种方式开始,但是现在大多数工具都具有其他抑制此类警告的机制。而且-不管它为什么开始,特别是在安全关键代码领域,这已成为“记录”开发人员意图的常用方法。
理查德·科登

5
GCC使用-Wall对此发出警告。
greyfade

23

强制转换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);

也可以。


1
除了它并不总是关闭编译器警告。海湾合作委员会似乎没有对铸造虚空做出回应
Matt

@Matt:您使用的是哪个版本的GCC?您可以将代码发布到ideone.com还是stacked-crooked.com(后者更好)。
纳瓦兹

1
标准的“废弃”措词是否暗示短绒不应该提出警告?
西罗Santilli郝海东冠状病六四事件法轮功2015年

2
@CiroSantilli巴拿马文件六四事件法轮功:....这是一个有趣的问题。目前,我不知道答案。如果您知道的话,请与我分享。
纳瓦兹


4

铸造成空是无价的。这只是编译器如何处理的信息。


1
如果编写代码以及随后的阅读,理解(然后忽略)代码的时间是免费的,那么这是“无成本的”。IMO,写作(void)花费了我很多时间和精力,让我想知道作者是否知道表情是如何工作的。
wallyk

4

对于您的程序而言,将功能强制转换为空是没有意义的。我还要指出,您不应该使用它来向正在阅读代码的人发信号,就像大卫回答中所建议的那样。如果您想传达有关您的意图的信息,最好使用评论。添加这样的演员表只会看起来很奇怪,并引起有关可能原因的疑问。只是我的观点...


2
这是一种已知的模式,可以明确地告诉其他人您不在乎返回值,而不仅仅是忘记处理它。
2014年

For the functionality of you program casting to void is meaningless对于自我记录和编译时的警告数量,实际上并非如此。当代码说明自己时,you should not use it to signal something to the person that is reading the code [...] it is better to use a comment.最好的注释是no comment。并且,再次使有效警告编译器满意。
underscore_d

“添加这样的演员只会看起来很奇怪,并引起关于可能原因的疑问”。我发现了其中之一,这就是为什么我正在读这篇文章。对我未经训练的大脑来说,就像是神秘的堆叠滥用行为。
mynameisnafe

1

同样,在验证代码是否符合MISTA(或其他)标准时,自动工具(如LDRA)将不允许您调用具有返回类型的函数而不返回值,除非您明确将返回值强制转换为(无效)


0

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();

我无法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中测试。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.