to describe the problem simply, please have a look at the code below:
int main()
{
int a=123;
({if (a) a=0;});
return 0;
}
I got this warning from [-Wsequence-point]
Line 4: warning: operation on 'a' may be undefined
my g++ version is 4.4.5
I'll appreciate whoever would explain this simple problem.
btw you could find my original program and original problem in #7 in this Chinese site (not necessary)
UPD1:
though to change the code into ({if(a) a=0; a;}) can avoid the warning, but I recognized that the real reason of the problem may not be The last thing in the compound statement should be an expression followed by a semicolon.
because the documentary also said If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.
an example can show it:
int main()
{
int a=123, b;
({;});
({if (a) b=0;});
return 0;
}
and this code got no warnings!
so I think the real reason is something about sequence point.
please help!
UPD2:
sorry to #AndyProwl for having unaccept his answer which was accepted before UPD1. following his advise I may ask a new question (UPD1 is a new question different from the original one). I'll accept his answer again because it surely avoids warnings anyhow.:)
If I decided to ask a new question, I'll update this question to add a link.
According to the C++ grammar, expressions (apart from lambda expressions perhaps, but that's a different story) cannot contain statements - including block statements. Therefore, I would say your code is ill-formed, and if GCC compiles it, it means this is a (strange) compiler extension.
You should consult the compiler's reference to figure out what semantics it is given (or not given, as the error message seems to suggest) to it.
EDIT:
As pointed out by Shafik Yaghmour in the comments, this appears to be a GNU extension. According to the documentation, the value of this "statement expression" is supposed to be the value of the last statement in the block, which should be an expression statement:
The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)
Since the block in your example does not contain an expression statement as the last statement, GCC does not know how to evaluate that "statement expression" (not to be confused with "expression statement" - that's what should appear last in a statement expression).
To prevent GCC from complaining, therefore, you should do something like:
({if (a) a=0; a;});
// ^^
But honestly, I do not understand why one would ever need this thing in C++.
Related
Suppose we have code like this:
int check(){
int x = 5;
++x; /* line 1.*/
return 0;
}
int main(){
return check();
}
If line 1 is commented out and the compiler is started with all warnings enabled, it emits:
warning: unused variable ‘x’ [-Wunused-variable]
However if we un-comment line 1, i.e. increase x, then no warning is emitted.
Why is that? Increasing the variable is not really using it.
This happen in both GCC and Clang for both c and c++.
Yes.
x++ is the same as x = x+1;, the assignment. When you are assigning to something, you possibly can not skip using it. The result is not discarded.
Also, from the online gcc manual, regarding -Wunused-variable option
Warn whenever a local or static variable is unused aside from its declaration.
So, when you comment the x++;, it satisfies the condition to generate and emit the warning message. When you uncomment, the usage is visible to the compiler (the "usefulness" of this particular "usage" is questionable, but, it's an usage, nonetheless) and no warning.
With the preincrement you are incrementing and assigning the value to the variable again. It is like:
x=x+1
As the gcc documentation says:
-Wunused-variable:
Warn whenever a local or static variable is unused aside from its declaration.
If you comment that line you are not using the variable aside of the line in which you declare it
increasing variable not really using it.
Sure this is using it. It's doing a read and a write access on the stored object. This operation doesn't have any effect in your simple toy code, and the optimizer might notice that and remove the variable altogether. But the logic behind the warning is much simpler: warn iff the variable is never used.
This has actually the benefit that you can silence that warning in cases where it makes sense:
void someCallback(void *data)
{
(void)data; // <- this "uses" data
// [...] handler code that doesn't need data
}
Why is that? increasing variable not really using it.
Yes, it is really using it. At least from the language point of view. I would hope that an optimizer removes all trace of the variable.
Sure, that particular use has no effect on the rest of the program, so the variable is indeed redundant. I would agree that warning in this case would be helpful. But that is not the purpose of the warning about being unused, that you mention.
However, consider that analyzing whether a particular variable has any effect on the execution of the program in general is quite difficult. There has to be a point where the compiler stops checking whether a variable is actually useful. It appears that the stages that generate warnings of the compilers that you tested only check whether the variable is used at least once. That once was the increment operation.
I think there is a misconception about the word 'using' and what the compiler means with that. When you have a ++i you are not only accessing the variable, you are even modifying it, and AFAIK this counts as 'use'.
There are limitations to what the compiler can identify as 'how' variables are being used, and if the statements make any sense. In fact both clang and gcc will try to remove unnecessary statements, depending on the -O-flag (sometimes too aggressively). But these optimizations happen without warnings.
Detecting a variable that is never ever accessed or used though (there is no further statement mentioning that variable) is rather easy.
I agree with you, it could generate a warning about this. I think it doesn't generate a warning, because developers of the compilers just didn't bothered handling this case (yet). Maybe it is because it is too complicated to do. But maybe they will do this in the future (hint: you can suggest them this warning).
Compilers getting more and more warnings. For example, there is -Wunused-but-set-variable in GCC (which is a "new" warning, introduced in GCC 4.6 in 2011), which warns about this:
void fn() {
int a;
a = 2;
}
So it is completely fine to expect that this emits a warning too (there is nothing different here, neither codes do anything useful):
void fn() {
int a = 1;
a++;
}
Maybe they could add a new warning, like -Wmeaningless-variable
As per C standard ISO/IEC 9899:201x, expressions evaluation are always executed to allow for expression's side effects to be produced unless the compiler can't be sufficiently sure that removing it the program execution is not altered.
5.1.2.3 Program execution
In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).
When removing the line
++x;
The compiler can deduce that the local variable x is defined and initialized, but not used.
When you add it, the expression itself can be considered a void expression, that must be evaluated for side effects, as stated in:
6.8.3 Expression and null statements
The expression in an expression statement is evaluated as a void expression for its side effects.
On the other hand to remove compiler warnings relative to unused variable is very common to cast the expression to void. I.e. for an unused parameter in a function you can write:
int MyFunc(int unused)
{
(void)unused;
...
return a;
}
In this case we have a void expression that reference the symbol unused.
recently I've stumbled on a bug as a result of the combination typo, comma-operator, default value. A term had a lot of parenthesis and commas. One comma was placed one parenthesis too far. The term was still a valid C++ code but the returned value was wrong.
In simplified version the error looked like this:
int intValue = MyString.toInt(),16;
The method toInt has a default parameter for number-base (default 10).
The variable intValue would be always 16.
So the question is, is there any style-guide rule to avoid such bugs or a c++ checker/compiler rule to help finding such bugs in code?
EDIT
Ok, I've changed the code a little bit to make more sense for comma:
char * MyString("0x42");
int intValue = stringToInt(MyString),16;
P.S.
Please don't blame me for not using std::string and streams. The code is only for simplified demonstration. :-)
With GCC, the -Wunused-value should give a warning in this case, as the return value of MyString.toInt() is not used. That flag should help avoid most such errors. To actually get the warning may require adding the __attribute__ ((warn_unused_result)) attribute to the toInt method.
In any case, as shown the simplified example causes an "expected unqualified-id before numeric constant" compile error unless parentheses are added as follows int intValue = (MyString.toInt(),16);
What I do is:
Readability and clarity always come first. Do not combine several simple expressions into a complex one. Instead, keep it simple. The fact that you post the simplified code, instead of the actual version, scares me. Anything that is too complex to post here should not go in your code.
Do not use default parameters. I don't find them to add much value for the readability they substract.
Do not use the comma operator.
Also, perform code reviews (the mere fact that a comma operator is present should have triggered a review comment); unit test your code; and use assertions to express preconditions and postconditions.
If you follow this advice, just reading your code after you type it will make erroneous lines scream at your eyes.
Sorry for the vague title, but not really sure how to phrase it. So I was looking through the innards of boost::asio (trying to track down some ridiculous delays), and I notice code like this dotted about:
op_queue<operation> completed_ops;
task_cleanup c = { this, &lock, &completed_ops };
(void)c; // EH?
Now from the name of the struct that is being initialized, I'm guessing it's using RAII to do some steps on destruction - fine, but what is the purpose of the last line? Have I just missed something completely funky?
Maybe to avoid a compilation warning because c isn't used?
It's probably there because it's a cross-platform method of getting the compiler not to complain about an unused variable.
The question was probably meant to be about why it's used, and that's already been answered. I'm going to talk about what it means (which the OP probably already knows, but others may not). At least one other question has been closed as a duplicate of this one.
In general, casting an expression to void evaluates the expression and discards the result, if any. In this case, the expression is c, the name of a variable of type task_cleanup (whatever that is).
An expression followed by a semicolon is an expression statement. When the statement is executed, the expression is evaluated and its result is discarded.
So this:
(void)c;
evaluates c (which, since c is just a non-volatile declared object, just fetches the value of the object), then discards the result, then discards the result again.
Semantically, this doesn't make much sense. You might as well just write:
c;
or even omit it entirely with exactly the same effect.
The purpose, as the other answers have already said, is to suppress a warning that the variable's value is not used. Without the cast, many compilers will warn that the result is discarded. With the cast, most compilers will assume that you're deliberately discarding the value, and will not warn about it.
This is no guarantee; compilers can warn about anything they like. But casting to void is a sufficiently widespread convention that most compilers will not issue a warning.
It probably would have been worthwhile to call the variable ignored rather than c, and a comment would definitely be helpful.
This question already has answers here:
When do extra parentheses have an effect, other than on operator precedence?
(2 answers)
Closed 3 years ago.
Usually auto-generated c++ "main" function has at the end
return (0);
or
return (EXIT_SUCCESS);
But why there are parentheses in above statements? Is it related to C language or something?
// EDIT
I know this is correct, but someone put these brackets for a reason. What's the reason?!
They are not required (even in c). I think some people use them to make 'return' look more like a function call, thinking it is more consistent.
Edit: It's likely the generator does this for it's own reasons. It may be safer or easier for it to work this way.
But why there are parentheses in above
statements? Is it related to C
language or something?
No. As far as I can tell, C has never required parentheses for return statements. This appears to have been the case even before the first ANSI C standard.
This is actually a very interesting question, however, as I've seen that style prevalent among certain C programmers.
I think the most likely guess as to why this style came about is because all other branching statements (for, while, if, switch) require parentheses around expressions. People might have been unaware that they could omit the parentheses for return statements or were aware of this but wanted to achieve a more uniform look to their code.
The ternary ?: operator is sort of an exception as it is an operator and doesn't require parentheses around the conditional expression, yet people often write parentheses there as well regardless of whether it's needed. Some might find it serves to 'group' an expression into a single unit visually.
My second best guess is that this style was influenced by other languages popular at the time. However, popular, procedural alternatives at the time like Pascal did not require that syntax either (Pascal did not even have return values in the C sense but only output parameters) so if this is the case, I'm not aware of any particularly language from which this style originated.
[Subjective] I prefer styles that require the least amount of superfluous decoration to the code whether it comes to naming conventions or how to format it or whether to use additional parentheses where unnecessary. I find that any such decoration tends to be a matter of unique personal preference and falling in love with one way of decorating code just means that someday you'll have to deal with a completely different way (unless you work strictly alone, in which case I envy you). [/Subjective]
This is actually a requirement for BSD kernel source file style.
man 9 style says:
Space after keywords (if, while, for, return, switch).
and
Values in return statements should be enclosed in parentheses.
As any valid expression can be passed to return, those brackets can be added if desired. It is like doing this:
int i = (0);
You can nest an expression in as many brackets as you like:
return (((((0)))));
Things changes with the use of decltype(auto) in c++14 to deduce return type. If parentheses are used then returned type is deduced to be a reference:
decltype(auto) foo1() {
int n;
return (n); // parentheses causes return type to be int&
}
decltype(auto) foo2() {
int n;
return n; // no parentheses causes return type to be int
}
template<typename T> struct TD;
int main()
{
// main.cpp:19:22: error: aggregate 'TD<int&()> f1' has incomplete type and cannot be defined TD<decltype(foo1)> f1;
TD<decltype(foo1)> f1;
// main.cpp:20:22: error: aggregate 'TD<int()> f2' has incomplete type and cannot be defined TD<decltype(foo2)> f2;
TD<decltype(foo2)> f2;
}
There's a dumb reason - to make return look more like a function call.
There's a smarter reason - if the code is generated, code generators often "play it safe" by putting parentheses around expressions just so they never have to be concerned about the precedence leaking out.
Just my silly speculation:
#define RETURN(val) { if (val) printf("Main Exit With Error %d\n", val); return val; }
int main(argc, argv)
{
...
RETURN (E_FILENOTFOUND);
}
Those are not required. Maybe they come from the tendency to prefer more brackets to fewer brackets when writing macros.
Since you mention auto-generated code it might happen that the code used for generating macros was written by reusing code for generating macros or by a person who thought that more brackets won't hurt, but fewer brackets can be fatal.
One reason I can see for this:
return (ERROR_SUCCESS);
is that it's expressing the concept that ERROR_SUCCESS is opaque. We all know it's 0L, but we shouldn't have to.
That's a fairly weak reason.
Another is that it's aesthetically pleasing to use parentheses for consistency, another weak reason.
So in other words, I don't use it myself, but wouldn't flip out if someone else did. :)
In C++ one can write any of the following statements:
10;
true;
someConstant; //if this is really an integer constant
or something like
int result = obtainResult();
result; // looks totally useless
The latter can be used to suppress a compiler warning "A variable is initialized but not referenced" (C4189 in VC++) if a macro that is expanded into an empty string in some configuration is later used with the result variable. Like this:
int result = obtainResult();
result;
assert( result > 0 ); // assert is often expanded into an empty string in Release versions of code
What's the meaning of such statements? How can they be used except for compiler warning suppression?
This kind of statements is a logical expansion of how other pieces of the language works. Consider having a function that returns a value, for example int foo(), that also has some side effects. Sometimes you only want those side effects to happen, so you write foo(); as a statement.
Now, while this does not look exactly like 10;, the function call will evaluate to an int sooner or later, and nothing happens to that int, just like with 10;.
Another example of the same issue is that since you can do a = b = 10;, that means b = 10 has to evaluate to 10, hence you can not do assignment without generating a value that has to be suppressed.
Being able to write such values as statements is just a logical way of building the language, but for the cases you present it might even be a good idea to give a compiler warning for it.
Unless you use it to suppress compiler warnings ;)
These statements (called expression-statements in the C++ grammar) are valid because they are expressions.
Expressions are all constructs that calculate some kind of value, such as
3 + 5
someVariable
someFunctionCall( 2 )
someVar += 62
val > 53
I think, to keep the grammar simple, they decided to not differentiate between those expressions that actually have a side effect (such as the function call or the assignment) and those that don't.
Such a statement does nothing, and will most likely be optimized away by any decent compiler.
It may be useful for getting rid of the unused variable warning, but with some compilers you may get a statement has no effect warning instead.
They have no practical use beyond compiler warning suppression, and in general the compiler will elide any such constant-value statement that has no side effect.
They are expressions that will be evaluated, assuming the compiler doesn't optimise them away. As for "meaning", I'm not sure what you "mean" by that!
In C and C++, a statement that is just an expression is evaluated.
The fact that the expression might be useless is harmless, and with the optimizer turned on can result in no code generated at all. However, as you've observed, it usually does count as use of a variable.
Note that statements containing only an expression are quite common. A simple function call is one, for example. In printf("hello, world.\n");, the return value of printf() is ignored but the function is still called and its intended effect (text output) happens.
Also, a variable assignment x = 3; is also a statement made up of a simple expression, since assignment is an operator and returns a value in addition to its side effect of modifying the lvalue.
Although legal I think these statements are confusing and should be avoided, even for suppressing warnings. For me it is more reasonable to suppress the warning using something like this:
int result = 0;
result = obtainResult();
assert (result > 0);
In some embedded enviroments accessing a read only register will have side effects, e.g. clearing it.
Writing int temp = IV; to clear it causes a warning because temp isn't used, in which case I write IV;
I agree with Magnus' answer. There is one thing that puzzles me though: why do you use this nonsense
int result = obtainResult();
result; // looks totally useless
to get rid of compiler warnings? In my humble opinion it is much worse NOT to have a warning in such situation. The result variable is still not used - you have just "swept the dirt under the carpet". This "lone variable" approach looks as if there was something missing (Have I accidently deleted something?). Why don't you use
(void)obtainResult();
in the first place? It assures anyone who would be reading your code that you do not care about the return result. It is very difficult to put this "accidently". Obviously this does not generate any compiler warnings.