I tried the following code in gcc:
#include<stdio.h>
int main()
{
int a=3,2,1;//////////////////////ERROR!//////////////////////////
printf("%d", a);
return 0;
}
I expected it to compile successfully as:
a series of integer expressions seperated by commas will be evaluated from left to right and the value of the right-most expression becomes the value of the total comma separated expression.
Then, the value of the integer variable a should have been 1 right? Or is it 3?
And why am I getting this error when I try to execute this program?
error: expected identifier or '(' before numeric constant
That's parsed as a three-part variable declaration, with two invalid variables.
You need to wrap the entire initializer in parentheses so that it's parsed as a single expression:
int a=(3,2,1);
If you separate the initialization from the declaration, you may get what you expected:
int a;
a = 3, 2, 1; // a == 3, see note bellow
or
int a;
a = (3, 2, 1); // a == 1, the rightmost operand of 3, 2, 1
as your original command is syntactically incorrect (it is the declaration so it expected other variables to declare instead of numbers 2 and 1)
Note: All side effects from the evaluation of the left-operand are completed before beginning the evaluation of the right operand.
So
a = 3, 2, 1
which are 3 comma operators a = 3, 2 and 1 are evaluated from left to right, so the first evaluation is
a = 3, 2
which result 2 (right-operand) (which is by the way not assigned to any variable, as the value of the left-operand a = 3 is simply 3), but before giving this result it is completed the side effect a = 3 of the left-operand, i. e. assigning 3 to variable a. (Thank AnT for his observation.)
Related
#include <stdio.h>
main() {
int pro;
int dot;
int tot;
char prelude[] = "\nNow we shall do some simple mathematics\n\n";
printf("%s", prelude);
pro = 3;
dot = 5;
tot = pro + dot;
printf("%d", tot);
dot += 23;
printf("\n%d\n", tot);
return 0;
}
Because C does not offer automatic data binding. When you use the assignment operator (or Addition assignment in your case), you are assigning the VALUE of the statement on the right hand side of the expression.
variable = statement means that statement will be calculated to some value, and this value will be assigned to variable according to variable's data type.
This means that you are assigning a value, not an actual statement to that variable.
To explain it better:
tot = pro + dot;
does the following:
I need to assign something that I must calculate to the variable tot.
Something is a statement, pro + dot.
This statement is an addition, an operation that takes two operands.
Operand 1 is pro, it evaluates to 3. (means that C will replace
pro with 3 in that statement)
Operand 2 is dot, it evaluates to 5.
All of the operands are evaluated.
The statement is: 3 + 5;
This evaluates to 8, an integer.
The expression has become tot = 8;
Assign the value 8 to tot. This means, go to the memory address
of the variable represented by tot, and write the integer 8 (in
accordance with the C standard/machine architecture).
If you do
dot += 23;
C understands this:
dot += 23; // can be translated to `dot = dot + 23;'
Like before:
dot means 8, 23 means 23.
statement: 8 + 23
The statement evaluates to 31. dot = 31;, meaning write the
integer 31 to the memory of dot.
Now tot , is unaffected by that. Why? Because tot is a space in your memory, that holds the value 8. It doesn't know that 8 was created by adding 2 other variables. It's just 8. So changing the other variables, will not affect this one.
If you do dot += 23;, you are changing the memory of the variable dot, not that of tot.
What you were expecting, is called data binding, and is a much higher level feature than what C offers.
The code snippet is:
int main()
{
int a = 1, b = 2, c = 3;
printf("%d", a += (a += 3, 5, a));
}
Though it displays 8 in the terminal as an output. But am not getting the concept behind it.
The expression a += (a += 3, 5, a) will invoke undefined behavior.
C standard says
C11: 6.5.16 Assignment operators (p3):
[...] The side effect of updating the stored value of the left operand is
sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
It is not guaranteed that whether the left most a will be evaluated before or after the evaluation of (a += 3, 5, a). That will result in undefined behavior.
This is an effect how the comma operator works, the last element is the one that is used as the value of the statement. So essentially what you got here is the following:
a += (a += 3, 5, a)
This evaluates a+=3 first, this makes a=4 this result is discarded, then evaluate 5 then this result is discarded, then evaluate a and keep this as it's the last item. The result from (a += 3, 5, a) is the last item which is a which is 4.
Then you get
a += 4
so a is 8.
Important Note: that this is an artifact of how your compiler has generated the code. The C standard doesn't guarantee the order of execution for the assignment to a in this situation. See haccks answer for more information about that.
As we know that comma has lowest precedence as operator so in,
a + = (a + = 3, 5, a) in this what will happen is first evaluation will be like this a+3 = 4 but then it will be discarded now evalutation will be a+5 = 6 now in third step we have to do a+a right
so here answer will be value from previous operation i.e. 6 and then
6+1 = 7 now we will come out of the brackets and we will do a = a+ 7 which is
a = 1 + 7 so answer will be 8
so therefore (a += 3,5,a) will get you 7 and a = a + 7 will get you 8 which will be printed finally
I have the following code which produces unexpected results to me:
#include < stdio.h >
int a = 0, value;
int main(void)
{
// Testing the evaluation order of multiple
// conditional operators:
value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
printf("%d\n", value);
return 0;
}
I was expecting for this code to print 3, seeing that the conditional operator evaluates
from right to left and that there is a sequence point at the ? of the first-to-be executed
operation, whereas it actually prints 5.
Is it wrong to assume that side effects of an expression residing between two sequence
points also get calculated when the values of the expressions are?
If i add printf("%d\n" a); i get 3 printed though, so the side effect gets done.
Or is it just that control dosent really pass to the subexpression the value of which
is being calculated "first" officially?
I would rather bet on the latter because changing the value of 'a' to 3 and the rvalue
in the assignment of the second conditional to 4 resulted in short-circuit evaluation
of the first conditional expression, meaning that i got 3 printed for both 'a' and 'value'.
I got the above result on Lubuntu 14.04 with GCC 4.8.2 using the -std=c99 flag.
Thank you for anyone clearing me up on this matter!
The conditional operator does not "evaluate right to left". The standard (C11 6.5.15/4) says:
The first operand is evaluated; there is a sequence point between its
evaluation and the evaluation of the second or third operand
(whichever is evaluated). The second operand is evaluated only if the
first compares unequal to 0; the third operand is evaluated only if the
first compares equal to 0; the result is the value of the second or
third operand (whichever is evaluated)
So the expression (a == 3) ? 3 : (a = 3) ? 5 : 0; evaluates in these steps:
(a == 3) result is 0
(a = 3) result is 3, unequal to 0
5
So 5 is what is assigned to value.
You might be confusing the concept of how the conditional operator is evaluated with how the conditional operator associates (or groups). The syntax of C specifies that the expression:
(a == 3) ? 3 : (a = 3) ? 5 : 0;
associates or groups sub expressions like so:
((a == 3) ? 3 : ((a = 3) ? 5 : 0));
which is often described as 'associates right'. However, this grouping/associativity doesn't affect the fact that the expression is still evaluated left-to-right and that the second conditional expression only evaluates after the first operand in the 'outer' conditional expression is evaluated.
Let's trace through this one part at a time. You have this expression:
value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
Since a starts off at 0, we skip the 3 branch of the first ?: and look at the second branch, which is
(a = 3) ? 5 : 0
The condition here is a = 3, which sets a to 3 and then evaluates to the new value of a, which is 3. Since 3 is nonzero, we take the first branch of the ?:, so the expression evaluates to 5. The net effect is that a is set to 3 and value is set to 5.
The language spec guarantees that the evaluation order is indeed what you think it should be - the "if" and "else" branches of the ?: operator are guaranteed not to execute unless the condition works out as it does, so there are sequence points here. I think you just misunderstood the effect of the a = 3 operation.
Hope this helps!
The conditional operator evaluates left-to-right (evaluating the condition before either of the branches). You may be confusing this with its right-associativity (in which it appears to bind right-to-left).
Your conditional expression essentially results in the following logic:
if(a == 3) {
value = 3;
} else {
if(a = 3) {
value = 5;
} else {
value = 0;
}
}
Note that the conditional doesn't execute a branch until after the condition is evaluated.
I have read that comma operator is used to assign expression, and the right expression is supplied to lvalue.
But why does this program assign left expression to lvalue when not using parenthesis? I am using turbo c compiler.
int b=2;
int a;
a=(b+2,b*5); // prints 10 as expected
a=b+2,b*5; // prints 4 when not using parenthesis
Also the following works:
int a =(b+2,b*5);
But this generates an error:
int a =b+2,b*5; // Error
I can't understand why.
Because precedence of , operator is lower than of = one, this...
a=b+2,b*5;
... will actually be evaluated as...
a = b + 2;
b * 5;
With int i = b + 2, b * 5; is a bit different, because comma has different meaning in declaration statements, separating different declarations from each other. Consider this:
int a = 3, b = 4;
You still have comma here, but now it separates two variable assignment-on-declarations. And that's how the compiler attempts to treat that line from your example - but fails to get any meaning from b * 5 line (it's neither assignment nor declaration).
Now, int a = (b + 2, b * 5) is different: you assign a value of b + 2, b * 5 expression to a variable a of type int. The first sub-expression is discarded, leaving you just with b * 5.
This gives compilation error.
int main(void)
{
int a = 1, 2, 3;
printf("%d", a);
return 0;
}
But,
int main(void)
{
int a;
a = 1, 2, 3;
printf("%d", a);
return 0;
}
prints 1. Why? I have no idea why this happens.
In your first code, comma is used as a separator.
In your second code, it's used as operator.
So, the first code is simply gives error.
In the precedence table, comma operator has the least precedence. So, in the second program,
a = 1, 2, 3
is equivalent to
(a = 1), 2, 3
As, a=1, 1 is printed.
The Wiki article for this one is just fine.
Ah the comma oprator :).
In C, the comma is an operator just like +, - * and /. This means it obeys rules of precendence, and it has a very low precedence (the lowest, in fact). Given that is has a lower precedence than the assignment operator, it is evaluated after any assignments in the same expression. When you type:
a = 1, 2, 3;
It evaluates the assignment, a = 1, and then the comma(s). This is equivalent to writing:
(a = 1), 2, 3;
If you were to place brackets in your code, the value assigned to a would differ would differ:
a = (1, 2, 3); // a now equals 3.
This is because the comma operator discards the left hand argument, and results in the right hand argument. So in this case, 1,2 evaluates to 2, and 2,3 evalues to 3.
The first example fails to compile because C supports the following syntax:
int a = 1, b = 2, c = 3;
Which declares 3 variables a, b and c, assigning values 1, 2 and 3, respectively. The combination of the = and , operators is confusing, hence why what you've written causes a compiler error. If you were to rewrite your assignment as follows:
int a = (1, 2, 3);
It clarifies the order of operations, and assigns the value 3 to a.
Here's a table showing operator precedence in C.
In the first line:
int a = 1, 2, 3;
you are attempting to declare variables 2 and 3 of type int, which i'n't allowed.
int a = 1, b, c; // OK
int a = 1, b = 2, c = 3; // OK
int a = (1, 2, 3); // OK - a == 3
In the second line:
a = 1, 2, 3;
you're using a comma operator; a is assigned 1 (not 3 as I first wrote; comma has the lowest of all operator precedences - and the 2 and 3 are thrown away).
As part of a declaration, a comma means that another declaration (of the same type) follows.
In your second example , it's the comma operator, which has very low precedence. It's equivalent to
(a = 1), 2, 3;
Because the standard says so:
(6.7) declaration:
declaration-specifiers init-declarator-listopt ;
(6.7) declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
(6.7) init-declarator-list:
init-declarator
init-declarator-list , init-declarator
(6.7) init-declarator:
declarator
declarator = initializer
(6.7.8) initializer:
assignment-expression
(6.5.16) assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
(6.5.17) expression:
assignment-expression
expression , assignment-expression
In the initializer (6.7) the comma is a separator. In the expression (6.5.17) the comma is an operator.