Greetings to all the expert again , and again I stumble across a few questions.
The Story :
I read a book mentions that a sequence point which is ; is a point where all the side effect before it should be evaluated before it advanced to the next statement.In order to make the context of my question clean , I will write a simple code.
The Code :
while (guess++ < 10)
{
printf("%d \n" , guests);
My Thinking and the Question:
1.)From the above code, the while statement test condition guess++ < 10 is a full expression.So in my mindset it is not a statement because it doesn't end with a ;.
2.)Since a postfix increment operator is used , therefore the guess value evaluated before it is incremented.
3.)The book mention that the increment operation is carry out right after the guess variable is used for the relational operation , then only the printf() function would carry out its duty.
4.)My question is that , since the test condition doesn't end with a ; , therefore it's not a statement . But why the increment operation implemented before printf() function is called , but not after the print() function only it is being incremented??
5.)Maybe this is a side question , the book mention that while is a structured statement , but why didn't I see a trailing ; is append on it while(testcondition);.
6.)It might sounds like a silly question , but sometime when I read some source code written by others , I will saw some of them place the open braces { of while loop on the same line with the while() , which causes it to be like that while(testcondition){ . Is this a convention or is there any special reason for doing this??
Thanks for spending time reading my problems , your help is much appreciated.
Answering question 1: The code between the brackets of a while loop is actually a full expression. From wikipedia:
This category includes expression statements (such as the assignment a=b;), return statements, the controlling expressions of if, switch, while, or do-while statements, and all three expressions in a for statement.
A good description of a full expression can be found in the C faq:
full expression
The complete expression that forms an expression statement, or one of the controlling expressions of an if, switch, while, for, or do/while statement, or the expression in an initializer or a return statement. A full expression is not part of a larger expression. (See ANSI Sec. 3.6 or ISO Sec. 6.6.)
It's important to note that a full expression has nothing to do with a statement or the semi-colon token.
So lets dig into this a little bit. Fixing up your code snippit I came up with this:
#include <stdio.h>
int main(void)
{
unsigned guess = 0;
while (guess++ < 10)
{
printf("%d " , guess);
}
return 0;
}
Which produces this output:
1 2 3 4 5 6 7 8 9 10
So that means that the evaluation would be equivalent to this code:
while (guess < 10)
{
guess++;
printf("%d " , guess);
}
The answer to question 5 can be found in this stackoverflow question:
In C/C++ why does the do while(expression); need a semi colon?
Related
I saw this question in a test in which we have to tell the output of the following code.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
The output is -1. I am unsure why this is the answer, though.
What does the expression +(+k--) mean in C?
This code is deeply, perhaps deliberately, confusing. It contains a narrowly-averted instance of the dread undefined behavior. It's hard to know whether the person who constructed this question was being very, very clever or very, very stupid. And the "lesson" this code might purport to teach or quiz you about -- namely, that the unary plus operator doesn't do much -- is not one that's important enough, I would think, to deserve this kind of subversive misdirection.
There are two confusing aspects of the code, the strange condition:
while(+(+k--)!=0)
and the demented statement it controls:
k=k++;
I'm going to cover the second part first.
If you have a variable like k that you want to increment by 1, C gives you not one, not two, not three, but four different ways to do it:
k = k + 1
k += 1
++k
k++
Despite this bounty (or perhaps because of it), some programmers get confused and cough out contortions like
k = k++;
If you can't figure out what this is supposed to do, don't worry: no one can. This expression contains two different attempts to alter k's value (the k = part, and the k++ part), and because there's no rule in C to say which of the attempted modifications "wins", an expression like this is formally undefined, meaning not only that it has no defined meaning, but that the whole program containing it is suspect.
Now, if you look very carefully, you'll see that in this particular program, the line k = k++ doesn't actually get executed, because (as we're about to see) the controlling condition is initially false, so the loop runs 0 times. So this particular program might not actually be undefined -- but it's still pathologically confusing.
See also these canonical SO answers to all questions concerning Undefined Behavior of this sort.
But you didn't ask about the k=k++ part. You asked about the first confusing part, the +(+k--)!=0 condition. This looks strange, because it is strange. No one would ever write such code in a real program. So there's not much reason to learn how to understand it. (Yes, it's true, exploring the boundaries of a system can help you learn about its fine points, but there's a line in my book between imaginative, thought-provoking explorations versus dunderheaded, abusive explorations, and this expression is pretty clearly on the wrong side of that line.)
Anyway, let's examine +(+k--)!=0. (And after doing so, let's forget all about it.) Any expression like this has to be understood from the inside out. I presume you know what
k--
does. It takes k's current value and "returns" it to the rest of the expression, and it more or less simultaneously decrements k, that is, it stores the quantity k-1 back into k.
But then what does the + do? This is unary plus, not binary plus. It's just like unary minus. You know that binary minus does subtraction: the expression
a - b
subtracts b from a. And you know that unary minus negates things: the expression
-a
gives you the negative of a. What unary + does is... basically nothing. +a gives you a's value, after changing positive values to positive and negative values to negative. So the expression
+k--
gives you whatever k-- gave you, that is, k's old value.
But we're not done, because we have
+(+k--)
This just takes whatever +k-- gave you, and applies unary + to it again. So it gives you whatever +k-- gave you, which was whatever k-- gave you, which was k's old value.
So in the end, the condition
while(+(+k--)!=0)
does exactly the same thing as the much more ordinary condition
while(k-- != 0)
would have done. (It also does the same thing as the even more complicated-looking condition while(+(+(+(+k--)))!=0) would have done. And those parentheses aren't really necessary; it also does the same thing as while(+ +k--!=0) would have done.)
Even figuring out what the "normal" condition
while(k-- != 0)
does is kind of tricky. There are sort of two things going on in this loop: As the loop runs potentially multiple times, we're going to:
keep doing k--, to make k smaller and smaller, but also
keep doing the body of the loop, whatever that does.
But we do the k-- part right away, before (or in the process of) deciding whether to take another trip through the loop. And remember that k-- "returns" the old value of k, before decrementing it. In this program, the initial value of k is 0. So k-- is going to "return" the old value 0, then update k to -1. But then the rest of the condition is != 0 -- and it's not true that 0 != 0. That is, 0 is equal to 0, so we won't make any trips through the loop, so we won't try to execute the problematic statement k=k++ at all.
In other words, in this particular loop, although I said that "there are sort of two things going on", it turns out that thing 1 happens one time, but thing 2 happens zero times.
At any rate, I hope it's now adequately clear why this poor excuse for a program ends up printing -1 as the final value of k. Normally, I don't like to answer quiz questions like this -- it feels like cheating -- but in this case, since I fundamentally disagree with the whole point of the exercise, I don't mind.
At first glance it looks like this code invokes undefined behavior however that is not the case.
First let's format the code correctly:
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
So now we can see that the statement k=k++; is inside of the loop.
Now let's trace the program:
When the loop condition is first evaluated, k has the value 0. The expression k-- has the current value of k, which is 0, and k is decremented as a side effect. So after this statement the value of k is -1.
The leading + on this expression has no effect on the value, so +k-- evaluated to 0 and similarly +(+k--) evaluates to 0.
Then the != operator is evaluated. Since 0!=0 is false, the body of the loop is not entered. Had the body been entered, you would invoke undefined behavior because k=k++ both reads and writes k without a sequence point. But the loop is not entered, so no UB.
Finally the value of k is printed which is -1.
Here's a version of this that shows operator precedence:
+(+(k--))
The two unary + operators don't do anything, so this expression is exactly equivalent to k--. The person that wrote this most likely was trying to mess with your mind.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
can someone explain to me why this code prints the decremented amount? Since (4 <= 3) is false, shouldn't it proceed to print "Hi"?
int main()
{
int amount = 4;
if((amount%5) <= (--amount))
printf("%d", amount);
else
printf("Hi");
}
Turns out this code is undefined. You've got the expression
(amount%5) <= (--amount)
But the key question is, does the amount%5 part use the old value of amount, or the new, after being decremented by the --amount part? And the answer is: We have no idea. There's no way to tell. There's no rule in the C language to tell us.
You might think the code has to be evaluated left-to-right, that the amount%5 part has to happen first, before the --amount part has a chance to happen. But that's not the way it works. Since it's undefined, anything could happen.
If it's evaluated more or less left-to-right, then we have
if(amount%5 <= --amount)
which evaluates to
if(4%5 <= --amount)
which evaluates to
if(4 <= --amount)
which evaluates to
if(4 <= 3)
which is false, so you might expect it to print "Hi". But, if it's evaluated more or less right-to-left, it's
if(amount%5 <= 3)
which evaluates to
if(3%5 <= 3)
which evaluates to
if(3 <= 3)
which is true.
(You'll notice that I have removed some extra parentheses, since they don't do anything.)
I hasten to add that these are not the only two possibilities. The rules say that once an expression is undefined, literally anything can happen -- the behavior doesn't have to be anything we might consider "reasonable" at all.
So why is it undefined? In this case it's because you have a variable -- amount -- which appears twice in the expression, and where one of those appearances is a modification (the --amount part), and where the other one uses the variable's value. The C Standard explicitly tells us that in this case (a) we can't tell whether the use of amount uses the old or the modified value, and furthermore that (b) this flaw in the expression -- this simultaneous modification and use -- renders the whole expression (and actually the whole program it's in) undefined.
So how do you fix it? The answer is simple, and it's the punchline of an old joke: Don't do that. Don't write expressions where a single variable (or other object) is both modified and used. It's fine to write --amount, just don't do it in an expression that's also using the value of the variable amount somewhere else.
Questions like this come up often. The canonical SO answers, which others are already redirecting you to, are collected under the question Why are these constructs (using ++) undefined behavior in C?. There's more I could say about the rules concerning undefined expressions, but you can find those details over at that question.
I will take an exam and my teacher asks weird C syntax rules. Like:
int q=5;
for(q=-2;q=-5;q+=3) { //assignment in condition part??
printf("%d",q); //prints -5
break;
}
Or
int d[][3][2]={4,5,6,7,8,9,10,11,12,13,14,15,16};
int i=-1;
int j;
j=d[i++][++i][++i];
printf("%d",j); //prints 4?? why j=d[0][0][0] ?
Or
extern int a;
int main() {
do {
do {
printf("%o",a); //prints 12
} while(!1);
} while(0);
return 0;
}
int a=10;
I could not find it rules any site or book. Really absurd and uncommon. Where can I find?
To me it seems that your teacher is asking questions which invole undefined behavior.
If you tell him that this is incorrect, you're directly confronting him.
However, you could do the following:
Compile the code on different platforms
Compile the code with different compilers
Compile the code with different versions of the same compiler
Build a matrix with the results. You'll find out that they differ
Show the results to your teacher ans ask him to explain why that happens
That way you do not say that he's wrong, you're just showing some facts and you're showing that you're willing to learn and work.
Do that a long before the exam so that the teacher can look into it and think about his questions so that he can change the exam in time.
I could not find it rules any site or book. Where can I find?
See Where do I find the current C or C++ standard documents?. If you have a good library at university, they should own a copy.
Concerning for(q=-2;q=-5;q+=3) {, all you need to do is to break this down into its components. q=-2 is ran first, then q=-5 is tested, and if that is not 0 (which it isn't since it's an expression with value -5), then the loop body runs once. Then break forces a premature exit from an otherwise infinite loop. The expression then q+=3 is never reached.
The behaviour of d[i++][++i][++i] is undefined. Tell your teacher that, tactfully.
The "%o" format denotes octal output. a is set to 10 in decimal which is 12 in octal. Your code would be clearer if you had written:
int a=012; // octal constant.
The online version of the C language standard has what you need (and is what I will be referring to in this answer); just bear in mind is is a language definition and not a tutorial, and as such may not be easy to read for someone who doesn't have a lot of experience yet.
Having said that, your teacher is throwing you a few foul balls. For example:
j=d[i++][++i][++i];
This statement results in undefined behavior for several reasons. The first several paragraphs of section 6.5 of the document linked above explain the problem, but in a nutshell:
Except in a few situations, C does not guarantee left-to-right evaluation of expressions; neither does it guarantee that side effects are applied immediately after evaluation;
Attempting to modify the value of an object more than once between sequence points1, or modifying and then trying to use the value of an object without an intervening sequence point, results in undefined behavior.
Basically, don't write anything of the form:
x = x++;
x++ * x++;
a[i] = i++;
a[i++] = i;
C does not guarantee that each ++i and i++ is evaluated from left to right, and it does not guarantee that the side effect of each evaluation is applied immediately. So the result of j[i++][++i][++i] is not well-defined, and the result will not be consistent over different programs, or even different builds of the same program2.
AND, on top of that, i++ evaluates to the current value of i; so clearly, your teacher's intent was for j[i++][++i][++i] to evaluate to j[-1][1][2], which would also result in undefined behavior since you're attempting to index outside of the array bounds.
This is why I hate, hate, hate it when teachers throw this kind of code at their students - not only is it needlessly confusing, not only does it encourage bad practice, but more often than not it's just plain wrong.
As for the other questions:
for(q=-2;q=-5;q+=3) { //assignment in condition part??
See sections 6.5.16 and 6.8.5.3. In short, an assignment expression has a value (the value of the left operand after any type conversions), and it can appear as part of a controlling expression in a for loop. As long as the result of the assignment is non-zero (as in the case above), the loop will execute.
printf("%o",a); //prints 12
See section 7.21.6.1. The o conversion specifier tells printf to format the integer value as octal: 1010 == 128
A sequence point is a point in a programs execution where an expression has been fully evaluated and any side effects have been applied. Sequence points occur at the ends of statements, between the evaluation of a function's parameters and the function call, after evaluating the left operand of the &&, ||, and ?: operators, and a few other places. See Annex C for the complete list.
Or even different runs of the same build, although in practice you won't see values change from run to run unless you're doing something really hinky.
This question already has answers here:
Yet Another Conditional Operator Nesting Question
(2 answers)
Why is the conditional operator right associative?
(3 answers)
To ternary or not to ternary? [closed]
(54 answers)
Closed 5 years ago.
I just got a question idea after having misunderstood a friend's statement.
My friend told me: I just taught a colleague how to do a if/else in one line in c.
Example:
int i = 0;
i < 0 ? printf("i is below 0") : printf("i is over or equal to 0");
For now, nothing new, it's called a ternary and most people know about that kind of statement BUT I first understood that:
I just taught a colleague how to do a IF / ELSE IF / ELSE in one line.
Since I don't / didn't know that doing such a thing is possible I tried to do something like
int i = 0;
i < 0 ? printf("i is below 0") : i == 0 ? printf("i equal 0") : printf("i is over 0");
Is it actually possible to do a if / else if / else "ternary". Or is there a way to do such a thing without having an horrible piece of code?
If you see e.g. this conditional expression reference you can see that the format of a "ternary expression" is
condition ? expression-true : expression-false
All three parts of the conditional expressions are, in turn, expressions. That means you can have almost any kind of expression, including nested conditional (ternary) expressions in them.
It should be noted that conditional expressions might make the code harder to read and understand, especially if used badly or if one attempt to put too much logic and nesting into the expressions.
This is definitely valid.
Or you could try something like this -
printf(i < 0 ? "i is below 0" : i == 0 ? "i equal 0" : "i is over 0");
C has both statements and expressions. There are two different kinds of syntactical things. BTW lines don't matter much in C (except for the preprocessor).
Expressions (like f(1,x+y) or even x=y++) are a special kind of statements (the most common one).
As an extension to C, the GCC compiler adds statement expressions, beyond what the C11 standard (read n1570) defines. Please download then read that n1570 repoort.
if is for conditional statements but the ternary ?: operator is for expressions (with all three operands being sub-expressions).
Some programming languages (notably Lisp, Haskell, Scheme, Ocaml) have only expressions and don't have any statements.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 5 years ago.
Here is my simple code ...
#include<stdio.h>
int main()
{
int i=5;
printf("%d %d %d %d %d ",i++,i--,++i,--i,i);
return 0;
}
On gcc,it gives output as '4 5 5 5 5'
but on TC,it gives output as '4 5 5 4 5'
what I know that in printf statement,evaluation will be from left to right if it is a single expression but in normal statement,it will be from left to right.
but if printf contain multiple expressions,then evaluation will be on stack,the elements would be pushed onto stack from left to right but popped out from right to left and that justified the TC output
Please correct me where am I wrong ???
C does not specify which order function arguments should be evaluated in, and so it is undefined and a compiler can do it however they choose, including arbitrarily and randomly. Bjarne Stroustrup says this explicitly in "The C++ Programming Language" 3rd edition section 6.2.2
He also gives a reason:
Better code can be generated in the absence of restrictions on expression evaluation order
I think the order in which the arguments of a function call are evaluated is not specified. As wikipedia says in this article on sequence points:
The order in which the arguments are evaluated is not specified
Modifying an object (in this code i) more than one time between the previous and the next sequence point is undefined behavior in C. Here the sequence point occurs at the function call after all arguments have been evaluated.
The two answers at this point in time invoke the unspecifiedness of the evaluation of function arguments. The correct answer is that your program is undefined because of side-effects to the same variable not separated by a sequence point.
Indeed, the evaluation order of function arguments is unspecified. This means that in the statement f(g(), h());, either g() is called before h() or it is called after.
However, unsequenced side-effects (as in your program) invoke undefined behavior, where anything can happen.
Bumping up an old topic but I just found how the gcc and Visual Studio Compiler works on multiple changes on the same variable in a statement so thought of sharing it here.
The compiler as defined here starts to implement stack method on the arguments being passed in printf which is 'i'. It follows these rules:-
1) Now it executes the pre-increments first therefore starting from right normal i then --i and then ++i are executed and the value of i after ++i is 5 so it implements these values (pops) so output is _ _ 5 5 5
2) Then it continues right to left and executes post increments therefore, i-- and then i++ so the value of i in the end is back to 5 but due to i-- it becomes 4 but shows 5 due to it being a post increment therefore the final output is 4 5 5 5 5 and the final value of i is 5
Hope I am able to clear your doubts.
TC doesn't follow this so it adheres to our human logic.