Working of the operators ++ followed by -> in the below example - c

Consider the code segment given below:
#include <stdio.h>
struct s
{
int x;
char c;
};
int main()
{
struct s x[2]={{1,'a'},{2,'b'}};
struct s * p;
p=x;
int a = p++ -> x; //line of doubt
printf("%d \n",a);
}
The output of the following code is 1 and it makes it clear that it is actually evaluated as :
int a = ((p++) -> x);
Now my question is, we know that in C , the binary -> operator is having higher precedence than the unary ++ operator. But why is the effect such that the ++ is grouped first and then the ->.
Is it so that being a binary operator it looks for the first operand to its left and it being p the pairing is done as :
int a= *(p++ -> x);
But this includes with p, p++ as a chunk and hence first p++ is considered, but I feel this explanation is a bit vague. Could anyone explain me the proper logic and along with it, could anyone recommend me any book from where I could practice more examples like this.
Edit:
Thanks for the answers, actually I have studied C from the texts "The C Programming Language" by Dennis Ritchie et. al and also from "C- The Complete Reference" by Hebert Schildt. In both the texts the operator precedence is as shown:
Source: "The C Programming Language (2nd Ed.)" by Dennis Ritchie et. al (pg. 53)

The postfix increment operator ++ and the member-access-via-pointer operator -> have the same precedence level, and they group left-to-right. So first p++ is evaluated, then (p++)->x.
Section 6.5.2p1 of the C standard gives the following syntax declaration for postfix operators:
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-listopt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
( type-name ) { initializer-list }
( type-name ) { initializer-list , }
Had you used the prefix increment operator, i.e. ++p->x, that has lower precedence than ->, grouping as ++(p->x). So you would end up getting the x member from the object p originally pointed to, then that member would be incremented with the expression evaluating to the incremented member.

Related

When to use arrow and when dot?

I've read about it and I mostly get it, but this situation confused me a bit. Why don't we use arrow operator -> in scanf? I understand that dot is used for objects and arrow for pointers but here, g is a pointer to structure.
DOCUMENT *take(int *pn){
DOCUMENT *g;
printf("How much documents? ");
scanf("%d", pn);
g = (DOCUMENT *)calloc(*pn, sizeof(DOCUMENT));
for (int i = 0; i < *pn; i++)
{
printf("Type in author, name of document and number of pages: ");
scanf("%s %s %d", g[i].author, g[i].name, &g[i].s );
}
return g;
}
The array index operator [] has a dereference built into it.
g[i] is exactly the same as *(g + i). So g[i] refers to a DOCUMENT, not a DOCUMENT * and thus you use the member access operator . instead of the pointer-to-member operator ->.
If the left operand of the . or -> is a pointer, then you use ->. Otherwise if it is an object (plain variable), then you use ..
In this case g[i] is taking a pointer and doing array subscripting on it. The result of that is an object ("lvalue"), not a pointer, hence g[i]..
Also note operator precedence in expressions like &g[i].s. The array subscripting operator [] and the struct member operator . have same operator precedence - they belong to the same group of postfix operators. But that group has left-to-right operator associativity so [] takes precedence over the .. Then after those two follow &, the unary address operator, with lowest operator precedence in the expression. So operator precedence guarantees that the expression is equivalent to &((g[i]).s).
The subscript operator used with a pointer yields the object pointed to by the pointer expression. That is, for example, this expression
g[i].author
(where g[i] is the i-th element of the array of structures) is equivalent to
( g + i )->author
where g + i is a pointer that points to the i-th element of the array of structures.
The subscript operator g[i] is equivalent to the expression *( g + i ).
You may write
g[i].author
or like
( *( g + i ) ).author
or like
( g + i )->author
Thus this call of scanf
scanf("%s %s %d", g[i].author, g[i].name, &g[i].s );
can be rewritten like
scanf("%s %s %d", ( g + i )->author, ( g + i )->name, &( g + i )->s );
When you write g[i], this is actually equal to *(g + i). That is, you dereference the pointer and it becomes an object again, so you can access it with dot (.) instead of arrow (->).

"error: lvalue required as left operand of assignment" in conditional operator

I'm new to C and today I learnt "?" operator which is the short type of if-else statement. However, when I execute this code:
int b;
int x;
b=3<2?x=12:x=34;
I get an error "error: lvalue required as left operand of assignment". I don't understand why it happens. Process in my mind is that the program first assigns 34 to x, then it assigns value of x,which is 34, to b.
On the other hand, I can use the statement as
int b;
int x;
b=3<2?x=12:(x=34);
without any errors. I looked to my book but nothing helped. Why can't I use the first statement? What is my computer trying to do?
Thanks...
+1 for interesting question - it highlights two differences between C++ and C.
(1) The evaluation rules for ternary expressions are different in C and C++
C++ parses as follows
logical-OR-expression ? expression : assignment-expression
It is therefore parsing your statement by matching assignment-expression to x=34
b = 3<2 ? x = 12 : (x = 34);
But C parses like this
logical-OR-expression ? expression : conditional-expression
x = 34 is not a conditional-expression so your statement gets parsed like
b = (3<2 ? x = 12 : x) = 34;
(2) The conditional operator in C++ can return an lvalue, whereas C cannot. Hence, the following is legal in C++ but not in C:
b = (3<2 ? x = 12 : x) = 34;
Verified on ideone.com for C and C++ compilers.
See also these links
Errors using ternary operator in c for diff between C and C++ ternary operator
Conditional operator differences between C and C++ for diff in lvalue rules

How is this C expression evaluated

Expression is:
foo = *p++
I am looking for a guide/reference with examples that can explain these things.
I understand postfix ++ has higher precedence than indirection *, so the expression is parsed as
*(p++)
But I am trying to get more clarity on the statement in GNU C reference manual Pg 40, that says:
Here p is incremented as a side effect of the expression, but foo takes the value of *(p++) rather than (*p)++, since the unary operators bind right to left.
In C/C++, precedence of Prefix ++ (or Prefix –) and dereference (*) operators is same, and precedence of Postfix ++ (or Postfix –) is higher than both Prefix ++ and *.
If p is a pointer then *p++ is equivalent to *(p++) (because postfix has higher precedence)
++*p is equivalent to ++(*p) (both Prefix ++ and * are right associative).
*++p is equivalent to *(++p) (both Prefix ++ and * are right associative).
You can see the below 2 programs to clarify your doubt.
Program 1
#include<stdio.h>
int main()
{
char arr[] = "overflow";
char *p = arr;
++*p;
printf(" %c", *p);
getchar();
return 0;
}
Output: p
Program 2
#include<stdio.h>
int main()
{
char arr[] = "overflow";
char *p = arr;
*p++;
printf(" %c", *p);
getchar();
return 0;
}
Output: v
The GNU quote is misleading (IMHO); from a language point-of-view it's nothing to do with left-to-right (or vice versa).*
The C language standard doesn't define things in terms of precedence or associativity (left-to-right or right-to-left); these are merely implied by the defined grammar. Postfix ++ is classified as a postfix-expression rather than a unary-expression:
postfix-expression:
primary-expression
[...]
postfix-expression ++
postfix-expression --
[...]
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
[...]
unary-operator:
& * + - ~ !
The interaction of the above production rules mean that your example is interpreted as *(p++).
In non-standardese, though, the reason is due to precedence, not associativity (which makes little sense for unary operators).
* In fact, the postfix operators are effectively left-to-right, which is the opposite of what's claimed.
The OP asked "how is evaluated" the expression *p++.
One thing is precedence and another different thing is evaluation.
The expression p++ increments the value of the variable p, but the value of the expression is he "old" value that p had.
For example, consider that p is char pointer used to analyze a string:
char s[] = "0123456789!";
char *p = s;
char q;
p = s; // Here *p == '0'
q = *p++ // Here q == '0' but *p == '1'
Although the precedence rules imply that *p++ is the same that *(p++), the value of *p++ is s[0], in despite of p == &s[1].
To be more precise, the value of the expression is the same as of *p.
In this case, the "side effects" are referring to the operations that are done over the objects, in this case we have the objects p and q in the expression q = *p++.
"Operation over objects" are not walking in the same path that "evaluation of expressions".
Saying that postfix and unary operators are right-associative (bind right to left) is just another way to express the fact that postfix operators have higher precedence in C than unary operators.

Assignment statement used in conditional operators

Can anybody please tell me why this statement is giving an error - Lvalue Required
(a>b?g=a:g=b);
but this one is correct
(a>b?g=a:(g=b));
where a , b and g are integer variables , and a and b are taken as input from keyboard.
In the expression,
(a > b ? g = a : g = b);
the relational operator > has the highest precedence, so a > b is grouped as an operand. The conditional-expression operator ? : has the next-highest precedence. Its first operand is a>b, and its second operand is g = a. However, the last operand of the conditional-expression operator is considered to be g rather than g = b, since this occurrence of g binds more closely to the conditional-expression operator than it does to the assignment operator. A syntax error occurs because = b does not have a left-hand operand (l-value).
You should use parentheses to prevent errors of this kind and produce more readable code which has been done in your second statement
(a > b ? g = a : (g = b));
in which last operand g = b of : ? has an l-value g and thats why it is correct.
Alternatively you can do
g = a > b ? a : b
The expression:
(a>b?g=a:g=b)
parsed as:
(a>b?g=a:g)=b
And we can't assign to an expression so its l-value error.
Read: Conditional operator differences between C and C++ Charles Bailey's answer:
Grammar for ?: is as follows:
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
This means that a ? b : c = d parses as (a ? b : c) = d even though (due to the 'not an l-value' rule) this can't result in a valid expression.
One side note:
Please keep space in you expression so that it become readable for example.
(a>b?g=a:g=b);
Should be written as:
(a > b? g = a: g = b);
similarly, you should add space after ; and ,.
The problem is operator precedence: In C the ternary conditional operator (?:) has a higher precedence than the assignment operator (=).
Without parenthesis (which don't do anything here) your expression would be this:
a > b ? g = a : g = b;
The operator with the highest precedence in there would be the comparison >, so this is where you'll get your first logical grouping:
(a > b) ? g = a : g = b;
The next highest expression is the ternary conditional, which results in the following expression:
((a > b) ? (g = a) : (g)) = b;
As you can see, you'll now end up with an lvalue (i.e. a value; not a variable) on the left side of your assignment operator, something that won't work.
As you already noticed, the solution to this is to simply group the expressions on your own. I'd even consider this good practice, especially if you're unsure how your precedence might play out. If you don't want to think about it, add parenthesis. Just keep code readability in mind, so if you can, resolve the operator precedence on your own, to ensure you've got everything right and readable.
As for readability: I'd probably use a classic if() here or move the assignment operator outside the ternary conditional, which is how you usually define max():
g = a > b ? a : b;
Or more general as a macro or inline function:
#define max(a, b) ((a) > (b) ? (a) : (b))
inline int max(int a, int b) {
return a > b ? a : b;
}
if(a>b)
{
g = a;
}
else
{
g = b;
}
that can be replaced with this
g = a > b ? a : b; //if a>b use the first (a) else use the second (b)
Your expression (a>b?g=a:g=b) is parsed as :
(a>b?g=a:g)=b
// ^^^
From the Microsoft documentation :
conditional-expression:
logical-or-expression
logical-or-expression ? expression : conditional-expression
In C, the operator ?: has an higher precedence that the operator =. Then it means that ( a ? b : c = d ) will be parsed as ( a ? b : c ) = d. Due to l-value's rule, the first expression is also valid but is not doing what you think.
To avoid this error, you can do also :
g = ( a > b ) ? a : b;
This question usually triggers a barrage of answers trying to explain the situation through the concept of operator precedence. In reality it cannot be explained that way, since this is a typical example of an input, on which surrogate concepts like "operator precedence" break down. As you probably know, there's really no "operator precedence" in C. There are only grammatical groupings, which generally cannot be expressed precisely through any linear ordering of operators.
Let's take a look at what the language specification says about it. The relevant portions of C grammar in this case are the grammars of ?: operator and = operator. For ?: operator it is
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
and for the = operator it is
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
In the first case the critical part is the last operand of ?: operator: it is not an expression, but rather a conditional-expression. The conditional-expression is a different entry point into the grammar of C expression: it "enters" the grammar at the point where it is no longer possible to include a top-level = operator into a conditional-expression. The only way to "smuggle" a = operator into a conditional-expression is to descend the grammar all the way to the very bottom
primary-expression:
identifier
constant
string-literal
( expression )
generic-selection
and then wrap around all the way to the top using the ( expression ) branch. This means that a conditional-expression can contain a = operator only when it is explicitly wrapped in (...). E.g. the grammar prohibits you from having g = b as the last operand of ?: operator. If you want something like that, you have to explicitly parenthesize it: <smth> ? <smth> : (g = b).
A very similar situation exists with the second piece of grammar: assignment operator. The left-hand side (LHS) of assignment is unary-expression. And unary-expression "enters" the general grammar of C expression at the point where it is too late to include a top level ?: operator. The only way to reach the ?: operator from unary-expression is to descend all the way down to primary-expression and take the ( expression ) branch. This means that grammar prohibits you from having a > b ? g = a : g as the LHS operand of = operator. If you want something like that, you have to explicitly parentesize it: (a > b ? g = a : g) = <smth>.
For this reason "popular" answers claiming that "operator precedence" makes the language to parse your expression as
(a > b ? g = a : g) = b
are actually completely incorrect. In reality, there's no derivation tree in formal C grammar that would make your input fit the syntax of C language. Your input is not parsable at all. It is not an expression. It is simply syntactically invalid. C language sees it as a syntactic gibberish.
Now, in practice you might see some implementations to respond with a "lvalue required as left operand of assignment" diagnostic message. Formally, this is a misleading diagnostic message. Since the above input does not satisfy the grammar of C language expression, there's no "assignment" in it, there's no "left operand" and there's no meaningful "lvalue" requirement.
Why do compilers issue this strange message? Most likely they do indeed parse this input as a valid C expression
(a > b ? g = a : g) = b
The result of ?: is never an lvalue in C, hence the error. However, this interpretation of your input is non-standard (extended?) behavior, which has no basis in formal C language. This behavior of specific implementations might be caused by their attempts to reconcile C and C++ grammars (which are quite different in this area), by their attempts to produce a more readable (albeit "fake") error message or by some other reason.
Typically, in such implementations a similar issue also would pop up in case of inputs like
a + b = 5
The same error would be issued, suggesting a (a + b) = 5 parse, while from the pedantic point of view a + b = 5 is not parsable as an expression at all (for the same reasons as described above).
Again, formally, this is not enough to say that the compiler is "broken": the compiler is required to detect a constraint violation and issue some diagnostic message, which is exactly what happens here. The fact that the text of the diagnostic message does not correctly reflect the nature of the problem is inconsequential (the compiler can simply say "Ha ha ha!"). But one undesirable consequence of such misleading diagnostics is that it misleads users into misinterpreting the problem, which is BTW painfully evident from the barrage of formally incorrect answers posted to this question.

Unclear behavior of "," operator in C

In a given code I found following sequence,
data = POC_P_Status, TE_OK;
I don't understand what that does mean.
Does the data element receive the first or the second element or something else?
Update:
I read somewhere that this behavior is like this,
if i would write that:
if(data = POC_P_Status, TE_OK) { ... }
then teh if clause will be true if TE_OK is true.
What do you mean?
It stores POC_P_Status into data.
i = a, b; // stores a into i.
This is equivalent to
(i = a), b;
because the comma operator has lower precedence than assignment.
It's equivalent to the following code:
data = POC_P_Status;
TE_OK;
In other words, it assigns POC_P_Status to data and evaluates to TE_OK.
In your first case, the expression stands alone, so TE_OK is meaningful only if it's a macro with side effects. In the second case, the expression is actually part of an if statement, so it always evaluates to the value of TE_OK. The statement could be rewritten as:
data = POC_P_Status;
if (TE_OK) { ... }
From the C11 draft (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf) :
The left operand of a comma operator is evaluated as a void
expression; there is a sequence point after its evaluation. Then the
right operand is evaluated; the result has its type and value. If
an attempt is made to modify the result of a comma operator or to
access it after the next sequence point, the behavior is undefined.
That means that in the expression:
a, b
The a is evaluated and thrown away, and then b is evaluated. The value of the whole expression is equal to b:
(a, b) == b
Comma operator is often used in places where multiple assignments are necessary but only one expression is allowed, such as for loops:
for (int i=0, z=length; i < z; i++, z--) {
// do things
}
Comma in other contexts, such as function calls and declarations, is not a comma operator:
int func(int a, int b) {...}
^
|
Not a comma operator
int a, b;
^
|
Not a comma operator

Resources