What does casting to `void` really do? [duplicate]
Asked Answered
A

4

77

An often used statement like (void)x; allows to suppress warnings about unused variable x. But if I try compiling the following, I get some results I don't quite understand:

int main()
{
    int x;
    (short)x;
    (void)x;
    (int)x;
}

Compiling this with g++, I get the following warnings:

$ g++ test.cpp -Wall -Wextra -o test
test.cpp: In function ‘int main()’:
test.cpp:4:13: warning: statement has no effect [-Wunused-value]
     (short)x;
             ^
test.cpp:6:11: warning: statement has no effect [-Wunused-value]
     (int)x;
           ^

So I conclude that casting to void is very different from casting to any other types, be the target type the same as decltype(x) or something different. My guess at possible explanations is:

  • It is just a convention that (void)x; but not the other casts will suppress warnings. All the statements equally don't have any effect.
  • This difference is somehow related to the fact that void x; isn't a valid statement while short x; is.

Which of these if any is more correct? If none, then how can the difference in compiler warnings be explained?

Auxin answered 15/12, 2015 at 12:6 Comment(3)
It is just a convention amongst compilers that this cast suppresses warnings. The C++ Standard does not mention warnings for "statement has no effect" at all.Gambado
@cigien although the questions are superficially similar, this one asks about the mechanism of the difference between casts to void and casts to other types, while the other asks about why one would want to do the cast to void. However, since this question has a satisfactory answer, I won't bother to alter it and vote to reopen. This comment is just to answer the auto-generated "Does this answer your question?". TLDR: nope.Auxin
I see what you're saying, and in general, I would keep "what" and "why" questions separate. But in this case, the "what does it do" is intimately tied to the "why do it" aspect, so I think it's worth linking them. There's no reason to do this (i.e. casting to void) other than to suppress a warning, and all answers on both posts basically say the same thing.Locative
S
77

Casting to void is used to suppress compiler warnings. The Standard says in §5.2.9/4 says,

Any expression can be explicitly converted to type “cv void.” The expression value is discarded.

Sauerbraten answered 15/12, 2015 at 12:13 Comment(1)
Could you update the link please? It doesn't go to the standard anymore, thank youSusa
P
34

This statement:

(void)x;

Says "Ignore the value of x." There is no such type as void - it is the absence of a type. So it's very different from this:

(int)x;

Which says "Treat x as if it were an integer." When the resulting integer is ignored, you get a warning (if it's enabled).

When you ignore something which is nothing, it is not considered a problem by GCC--and with good reason, since casting to void is an idiomatic way to ignore a variable explicitly in C and C++.

Phonologist answered 15/12, 2015 at 12:9 Comment(11)
I never thought about it like that but I am slightly confused, do you think you could give an example to clarify the concept of casting a variable to a void?Hemipode
I'm pretty sure there is "such a type as void". See [basic.types].Dupondius
@Sacert: (void)x is casting a variable to void. You said it yourself. But once you've done that, you can do nothing more with it, because a void expression has no value.Phonologist
@JohnZwinck Right so I can't seem to wrap my head around why someone would want to do that? Is there ever a case where that is useful?Hemipode
@Sacert: You have already identified the case where it is useful: explicitly ignoring a variable, or a return value.Phonologist
It's much more useful to cast a return result to void ((void)foo()) to say you are deliberately ignoring the return value. The only time I can image casting a variable to void is if the variable is only used inside some #ifdef code, and you want to suppress the warning when the code is not included.Stylographic
@MartinBonner: Yes, casting a variable to void is typically done when the variable is only used in an assert() so would otherwise produce warnings in release builds.Phonologist
From void f() you can return any of (void) x, void(y), void() (maybe per void(void)?) or any g() that returns void itself. This way R f(int z) { return R(z); } covers void and nonvoid R.Outing
"There is no such type as void". This is wrong. void is an incomplete type that cannot be completed. It is a type.While
@AyxanHaqverdili Interesting, is it the only such type? I would have asked "a type of what" since it's guaranteed not to describe a value, but I'm guessing it's more of a categorical distinction.Outing
@JohnP It's an incomplete type (like what you get when you do class Foo; without a body). Incomplete types cannot be instantiated. But in addition, you are not allowed to define and make it complete. So, it's a special type, but it's still a type. I don't know of any other type with that property.While
C
13

The standard does not mandate generating a warning ("diagnostic" in standardese) for unused local variables or function parameters. Likewise, it does not mandate how such a warning might be suppressed. Casting a variable expression to void to suppress this warning has become an idiom in the C and later C++ community instead because the result cannot be used in any way (other than e.g. (int)x), so it's unlikely that the corresponding code is just missing. E.g.:

(int)x;  // maybe you meant f((int)x);
(void)x; // cannot have intended f((void)x);
(void)x; // but remote possibility: f((void*)x);

Personally, I find this convention too obscure still, which is why I prefer to use a function template:

template<typename T>
inline void ignore(const T&) {} // e.g. ignore(x);

The idiomatic way to ignore function parameters is, however, to omit their name (as seen above). A frequent use I have for this function is when I need to be able to name a function parameter in conditionally compiled code such as an assert. I find e.g. the following more legible than the use of #ifdef NDEBUG:

void rate(bool fantastic)
{
    assert(fantastic);
    ignore(fantastic);
}
Comnenus answered 15/12, 2015 at 13:16 Comment(1)
Since C++17 you can use [[maybe_unused]] attribute instead of all these "creative" ways to ignore a parameter.Auxin
E
2

Possible use:

auto it = list_.before_begin();
for (auto& entry : list_)
{
    (void)entry; //suppress warning
    ++it;
}

Now the iterator 'it' points to the last element

Exaction answered 9/1, 2019 at 11:33 Comment(2)
The question was not "when is it useful", but rather "what does it do".Auxin
e.g. like mentioned in the comment: "supress warning"Exaction

© 2022 - 2024 — McMap. All rights reserved.