在函数调用之前使用(void)

42

可能是重复问题:
如何将未使用的返回值转换为void

在函数调用前加上(void)的目的是什么,例如:

(void)func1();

我认为这与直接调用func1();相同。

因此,(void)调用是否只是为了让其他程序员知道返回类型将被忽略,例如如果func1()的返回类型为int,还是编译器可能对函数进行一些优化?也许有其他原因 - 它是否合法的C ++代码,或者它是否是在某些遗留代码中看到的C的残留物。

谢谢


4
可能是 casting unused return values to void 的重复问题,还有很多其他类似的问题... 不管怎样,我认为程序员不应该在代码中加入垃圾代码只是为了让“他们”的编译器高兴,因为“他们”所支持的无用或愚蠢警告对于编译器来说是无用的。至于“明确表明我们不关心表达式的结果”,既然我们没有对其进行任何操作,那不是显而易见吗? - effeffe
4
这不是垃圾代码,也不是程序员让编译器闭嘴。这是程序员告诉代码阅读者:“我知道这个函数有返回值,但我不在意”。与“func1();”相反,它的意思是“要么我知道这个函数有返回值但我不在意,要么我忘记正确地处理返回类型,从而造成致命错误”。出于同样的原因,编译器警告未处理的返回类型永远不会是无用/愚蠢的。 - Lundin
4
@Lundin,你通常会写成(void) printf("hello");吗? - effeffe
@Lundin 嗯,我不喜欢在我的代码风格选择上不一致,但这只是个人口味问题。我更喜欢认为人们在使用函数之前会阅读文档,但你的选择也有道理,尽管我认为大多数人这样做是为了让编译器闭嘴(事实上,这个问题及其重复的答案几乎都是这么说的)。 - effeffe
@effeffe,你通常写scanf("%d", &x)吗?或者你在生产代码中没有使用scanf... - Lundin
显示剩余2条评论
4个回答

27

如果一个值是逗号操作符的操作数并且覆盖了逗号操作符,那么将其转换为void会抑制它,在这种情况下,将其转换为void可能具有语义效果:

struct S {
  int operator,(int) { return 0; }
};
std::cout << (S(), 42) << '\n';           // prints '0'
std::cout << ((void) S(), 42) << '\n';    // prints '42'

+1(我希望我能付出更多)。在这篇文章中,我看到的所有答案中,这是一个很好的功能性做法。它实际上意味着除了其他答案似乎都集中在“没有什么可看的”和“闭嘴,愚蠢的编译器”之外。感谢您提供这个答案。 - WhozCraig
1
我不知道C++中有这个目的。对于C程序员来说,还有另一个目的;他们这样做是为了避免编译器警告,如“未使用的返回值”。 - Jack

26

谢谢!我本来以为会有更有用的理由来使用它。 - const_ref
2
请注意,如果一个函数已经以这种方式声明,那么很可能是有充分的理由的。因此,您应该添加一个检查返回值而不是无视它。 - datenwolf
1
@datenwolf:你上次检查printf的返回结果是什么时候? :-) - Kerrek SB
1
@KerrekSB 他说的是使用该属性声明的函数,而不是一般声明返回值的函数。我希望没有一个合理的标准库会用这样的垃圾属性声明 printf 函数。 - Christian Rau
即使编译器没有抱怨printf(...)(void) printf(...)之间的差异,其他工具如lint也会。请注意:我并不提倡这种做法。 - David Hammen
@KerrekSB,你上次检查scanf返回的结果是什么时候?另外,如果printf的返回值不是如此无用的信息,人们实际上会检查它。这是一个非常奇怪的函数。 - Lundin

5

这句话实际上没有什么意义。它明确将该行转换为一个空表达式,即仅用于其副作用且其值被丢弃的表达式。因此,这些代码行:

func1();

并且

(void)func1();

这将执行相同的操作。如果编译器知道表达式的值未被使用,则可以执行一些优化,但很可能编译器可以在有或没有显式(void)的情况下找出它。

它可以用作文档形式,程序员试图让它明显地表明他们没有使用表达式的值。


正如我所想的那样,出于可读性的考虑,使用它是有意义的。 - const_ref
什么意思是在函数调用前添加void? - Arunprasad Rajkumar

3
另一个奇怪的用法是允许未知返回类型的函数在逗号运算符旁边使用作为序列运算符。例如,decltype(f(), g()) 技术,其中您想要说“f 可以使用 () 进行操作,同样可以使用 g,并且我希望该类型是 g() 返回的类型”。但是,如果 f() 返回的类型使得 operator, 被重载,则结果将是意外的。
所以你需要使用 decltype(void(f()), g()),在调用 operator, 之前丢弃 f() 的返回值,这样您就保证会得到内置的序列运算符而不是某个未知的覆盖类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接