Beginner in need of a simple explanation of the difference between order of evaluation and precedence/associativityWhy are these constructs using pre and post-increment undefined behavior?Why does a=(b++) have the same behavior as a=b++?Operator Precedence vs Order of EvaluationOperator Precedence vs Order of EvaluationPrecedence of && over ||Who defines C operator precedence and associativity?Associativity of function call operator in CWhat is the difference between a sequence point and operator precedence?Ternary operator in loop conditional: evaluation order / op. precedence unclearHow to justify C postfix increment operator with precedence table?*p++->str : Understanding evaluation of ->
What is a "soap"?
Graphs for which a calculus student can reasonably compute the arclength
How do some PhD students get 10+ papers? Is that what I need for landing good faculty position?
Are those flyers about apartment purchase a scam?
Swap on SSD in 2019?
Who invented Monoid?
If you know the location of an invisible creature, can you attack it?
Boss wants me to ignore a software API license prohibiting mass download
How to remove ambiguity: "... lives in the city of H, the capital of the province of NS, WHERE the unemployment rate is ..."?
How can God warn people of the upcoming rapture without disrupting society?
Are differences between uniformly distributed numbers uniformly distributed?
Tempoverlustspiel
If "more guns less crime", how do gun advocates explain that the EU has less crime than the US?
How should I write this passage to make it the most readable?
How big are the Choedan Kal?
Running code generated in realtime in JavaScript with eval()
What would it take to get a message to another star?
How would timezones work on a planet 100 times the size of our Earth
The cat exchanges places with a drawing of the cat
Can a bald person be a Nazir?
What can Amex do if I cancel their card after using the sign up bonus miles?
Why aren't rainbows blurred-out into nothing after they are produced?
Do Reform Jews believe in a theistic God?
What kind of liquid can be seen 'leaking' from the upper surface of the wing of a Boeing 737-800?
Beginner in need of a simple explanation of the difference between order of evaluation and precedence/associativity
Why are these constructs using pre and post-increment undefined behavior?Why does a=(b++) have the same behavior as a=b++?Operator Precedence vs Order of EvaluationOperator Precedence vs Order of EvaluationPrecedence of && over ||Who defines C operator precedence and associativity?Associativity of function call operator in CWhat is the difference between a sequence point and operator precedence?Ternary operator in loop conditional: evaluation order / op. precedence unclearHow to justify C postfix increment operator with precedence table?*p++->str : Understanding evaluation of ->
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I am reading the end of the 2nd chapter of K&R and I'm having some difficulty understanding two specific unrelated example lines of code (which follow) along with commentary of them in the book:
x = f() + g();
a[i] = i++;
FIRST LINE - I have no trouble understanding that the standard does not specify the order of evaluation for the +
operator, and that therefore it is unspecified whether f()
or g()
evaluates first (and that is why I think the question isn't a duplicate). My confusion stems from the fact that if we look up the C operator precedence chart it cites function calls as of highest precedence with left-to-right associativity. Now doesn't that mean that f()
has to be called/evaluated before g()
? Obviously not, but I don't know what I am missing.
SECOND LINE - Again the similar conundrum regarding whether the array is indexed to the initial value of i
or the inceremented value. However, again the operator precedence chart cites array subscripting as of highest precedence with left-to-right associativity. Therefore wouldn't array subscripting be the first thing to be evaluated causing the array to be subscripted to the initial value of i
and removing any unambiguity? Obviously not, and I'm missing something.
I do understand that compilers have the freedom to decide when side effects happen in an expression (between sequence points of course) and that that may cause undefined behaviour if the variable in question is used again in the same expression, however in the examples above it seems that any ambiguity is cleared by function calls and array subscripting having highest precedence and defined left-to-right associativity, so I fail to see the ambiguity.
I have a feeling that I have some fundamental misconception about the concepts of associativity, operator precedence and order of evaluation, but I can't point my finger on what it is, and similar questions/answers on this topic were out of my league to understand thoroughly at this point.
I don't think this question is a duplicate even though I'm not the first one to be confused by this on this forum, I believe that this question wasn't asked in this fashion before.
c
add a comment |
I am reading the end of the 2nd chapter of K&R and I'm having some difficulty understanding two specific unrelated example lines of code (which follow) along with commentary of them in the book:
x = f() + g();
a[i] = i++;
FIRST LINE - I have no trouble understanding that the standard does not specify the order of evaluation for the +
operator, and that therefore it is unspecified whether f()
or g()
evaluates first (and that is why I think the question isn't a duplicate). My confusion stems from the fact that if we look up the C operator precedence chart it cites function calls as of highest precedence with left-to-right associativity. Now doesn't that mean that f()
has to be called/evaluated before g()
? Obviously not, but I don't know what I am missing.
SECOND LINE - Again the similar conundrum regarding whether the array is indexed to the initial value of i
or the inceremented value. However, again the operator precedence chart cites array subscripting as of highest precedence with left-to-right associativity. Therefore wouldn't array subscripting be the first thing to be evaluated causing the array to be subscripted to the initial value of i
and removing any unambiguity? Obviously not, and I'm missing something.
I do understand that compilers have the freedom to decide when side effects happen in an expression (between sequence points of course) and that that may cause undefined behaviour if the variable in question is used again in the same expression, however in the examples above it seems that any ambiguity is cleared by function calls and array subscripting having highest precedence and defined left-to-right associativity, so I fail to see the ambiguity.
I have a feeling that I have some fundamental misconception about the concepts of associativity, operator precedence and order of evaluation, but I can't point my finger on what it is, and similar questions/answers on this topic were out of my league to understand thoroughly at this point.
I don't think this question is a duplicate even though I'm not the first one to be confused by this on this forum, I believe that this question wasn't asked in this fashion before.
c
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.f()
andg()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.
– tadman
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago
add a comment |
I am reading the end of the 2nd chapter of K&R and I'm having some difficulty understanding two specific unrelated example lines of code (which follow) along with commentary of them in the book:
x = f() + g();
a[i] = i++;
FIRST LINE - I have no trouble understanding that the standard does not specify the order of evaluation for the +
operator, and that therefore it is unspecified whether f()
or g()
evaluates first (and that is why I think the question isn't a duplicate). My confusion stems from the fact that if we look up the C operator precedence chart it cites function calls as of highest precedence with left-to-right associativity. Now doesn't that mean that f()
has to be called/evaluated before g()
? Obviously not, but I don't know what I am missing.
SECOND LINE - Again the similar conundrum regarding whether the array is indexed to the initial value of i
or the inceremented value. However, again the operator precedence chart cites array subscripting as of highest precedence with left-to-right associativity. Therefore wouldn't array subscripting be the first thing to be evaluated causing the array to be subscripted to the initial value of i
and removing any unambiguity? Obviously not, and I'm missing something.
I do understand that compilers have the freedom to decide when side effects happen in an expression (between sequence points of course) and that that may cause undefined behaviour if the variable in question is used again in the same expression, however in the examples above it seems that any ambiguity is cleared by function calls and array subscripting having highest precedence and defined left-to-right associativity, so I fail to see the ambiguity.
I have a feeling that I have some fundamental misconception about the concepts of associativity, operator precedence and order of evaluation, but I can't point my finger on what it is, and similar questions/answers on this topic were out of my league to understand thoroughly at this point.
I don't think this question is a duplicate even though I'm not the first one to be confused by this on this forum, I believe that this question wasn't asked in this fashion before.
c
I am reading the end of the 2nd chapter of K&R and I'm having some difficulty understanding two specific unrelated example lines of code (which follow) along with commentary of them in the book:
x = f() + g();
a[i] = i++;
FIRST LINE - I have no trouble understanding that the standard does not specify the order of evaluation for the +
operator, and that therefore it is unspecified whether f()
or g()
evaluates first (and that is why I think the question isn't a duplicate). My confusion stems from the fact that if we look up the C operator precedence chart it cites function calls as of highest precedence with left-to-right associativity. Now doesn't that mean that f()
has to be called/evaluated before g()
? Obviously not, but I don't know what I am missing.
SECOND LINE - Again the similar conundrum regarding whether the array is indexed to the initial value of i
or the inceremented value. However, again the operator precedence chart cites array subscripting as of highest precedence with left-to-right associativity. Therefore wouldn't array subscripting be the first thing to be evaluated causing the array to be subscripted to the initial value of i
and removing any unambiguity? Obviously not, and I'm missing something.
I do understand that compilers have the freedom to decide when side effects happen in an expression (between sequence points of course) and that that may cause undefined behaviour if the variable in question is used again in the same expression, however in the examples above it seems that any ambiguity is cleared by function calls and array subscripting having highest precedence and defined left-to-right associativity, so I fail to see the ambiguity.
I have a feeling that I have some fundamental misconception about the concepts of associativity, operator precedence and order of evaluation, but I can't point my finger on what it is, and similar questions/answers on this topic were out of my league to understand thoroughly at this point.
I don't think this question is a duplicate even though I'm not the first one to be confused by this on this forum, I believe that this question wasn't asked in this fashion before.
c
c
asked 9 hours ago
ahraahra
1485 bronze badges
1485 bronze badges
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.f()
andg()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.
– tadman
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago
add a comment |
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.f()
andg()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.
– tadman
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.
f()
and g()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.– tadman
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.
f()
and g()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.– tadman
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago
add a comment |
5 Answers
5
active
oldest
votes
FIRST LINE
The left-to-right associativity means that an expression such as f()()()
is evaluated as ((f())())()
. The associativity of the function call operator ()
says nothing about its relationship with other operators such as +
.
(Note that with unary operators, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that []
has higher precedence than =
means that the expression is parsed as (a[i]) = (i++)
. It says very little about evaluation order; a[i]
and i++
must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c
is parsed as (a + b) + c
(left-to-right) or as a + (b + c)
(right-to-left).
Precedence also controls parsing and tells you whether a + b * c
is parsed as (a + b) * c
(+
has higher precedence than *
) or as a + (b * c)
(*
has higher precedence than +
).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
1
Associativity is not relevant tof()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation likea-b+c
where there could (based on precedence alone) be a choice between(a-b)+c
ora-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)
– Eric Postpischil
7 hours ago
add a comment |
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c
, a + (b + c)
, or (b + c) + a
.
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since *
has higher precedence than +
, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y
overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
add a comment |
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the +
and -
operators have the same precedence level, so a + b
is first evaluated, then a + b - c
.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x
must be called first, then the function pointer returned by x
is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i
on the left side may be evaluated before or after the side effect of ++
. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
add a comment |
- It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would apply to single calls like
f()
, or nested calls likef(g())
. It wouldn't say anything about two separate function calls on either side of a+
operator. - Precedence and associativity don't help us at all in the expression
a[i] = i++
. There simply is no rule that says precisely wheni++
stores the new result back intoi
, meaning that there is no rule to tell us whether thea[i]
part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c
, does the +
or the *
apply first? In *p++
, does the *
or the ++
apply first? Precedence answers these questions.
Associativity tells you what happens when you have a string of the same operators in a row. In a + b + c
, which +
applies first?
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f)
, there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
In a + b * c
precedence tells us that the multiplication happens before the addition, and in a + b + c
, associativity tells us that the left-hand addition happens before the right-hand one. But in f() + g() + x() * y()
there's nothing to tell us which order the function calls happen in, even though (once they've been called) precedence and associativity tell us in what order their return values will be multiplied and added together.
See also this answer which, although it's about a different question, explains the same points in more detail.
add a comment |
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z
. The additive operators +
and -
are left-associative, so that sequence is parsed as (x + y) - z
- IOW, the result of z
is subtracted from the result of x + y
.
THIS DOES NOT MEAN that any of x
, y
, or z
have to be evaluated in any particular order. It does not mean that x + y
must be evaluated before z
. It only means that the result of x + y
must be known before the result of z
is subtracted from it.
Regarding x = f() + g()
, all that matters is that the results of f()
and g()
are known before they can be added together - it does not mean that f()
must be evaluated before g()
. And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i]
and i++
are unsequenced with respect to each other). You cannot both update an object (i++
) and use its value in a computation (a[i]
) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++
(or a[i++] = i
) and x = x++
all have undefined behavior, and the result can be quite literally anything.
Note that the &&
, ||
, ?:
, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++
will be evaluated first and its side effect will be applied before a[i]
is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators +
and -
is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression
can produce a single multiplicative-expression
, or it can produce another additive-expression
followed by an additive operator followed by a multiplicative-expression
. Let's see how this plays out with x + y - z
:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y
is grouped together into an additive-expression
first, and then that expression is grouped with z
to form another additive-expression
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57484829%2fbeginner-in-need-of-a-simple-explanation-of-the-difference-between-order-of-eval%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
FIRST LINE
The left-to-right associativity means that an expression such as f()()()
is evaluated as ((f())())()
. The associativity of the function call operator ()
says nothing about its relationship with other operators such as +
.
(Note that with unary operators, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that []
has higher precedence than =
means that the expression is parsed as (a[i]) = (i++)
. It says very little about evaluation order; a[i]
and i++
must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c
is parsed as (a + b) + c
(left-to-right) or as a + (b + c)
(right-to-left).
Precedence also controls parsing and tells you whether a + b * c
is parsed as (a + b) * c
(+
has higher precedence than *
) or as a + (b * c)
(*
has higher precedence than +
).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
1
Associativity is not relevant tof()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation likea-b+c
where there could (based on precedence alone) be a choice between(a-b)+c
ora-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)
– Eric Postpischil
7 hours ago
add a comment |
FIRST LINE
The left-to-right associativity means that an expression such as f()()()
is evaluated as ((f())())()
. The associativity of the function call operator ()
says nothing about its relationship with other operators such as +
.
(Note that with unary operators, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that []
has higher precedence than =
means that the expression is parsed as (a[i]) = (i++)
. It says very little about evaluation order; a[i]
and i++
must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c
is parsed as (a + b) + c
(left-to-right) or as a + (b + c)
(right-to-left).
Precedence also controls parsing and tells you whether a + b * c
is parsed as (a + b) * c
(+
has higher precedence than *
) or as a + (b * c)
(*
has higher precedence than +
).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
1
Associativity is not relevant tof()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation likea-b+c
where there could (based on precedence alone) be a choice between(a-b)+c
ora-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)
– Eric Postpischil
7 hours ago
add a comment |
FIRST LINE
The left-to-right associativity means that an expression such as f()()()
is evaluated as ((f())())()
. The associativity of the function call operator ()
says nothing about its relationship with other operators such as +
.
(Note that with unary operators, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that []
has higher precedence than =
means that the expression is parsed as (a[i]) = (i++)
. It says very little about evaluation order; a[i]
and i++
must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c
is parsed as (a + b) + c
(left-to-right) or as a + (b + c)
(right-to-left).
Precedence also controls parsing and tells you whether a + b * c
is parsed as (a + b) * c
(+
has higher precedence than *
) or as a + (b * c)
(*
has higher precedence than +
).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
FIRST LINE
The left-to-right associativity means that an expression such as f()()()
is evaluated as ((f())())()
. The associativity of the function call operator ()
says nothing about its relationship with other operators such as +
.
(Note that with unary operators, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that []
has higher precedence than =
means that the expression is parsed as (a[i]) = (i++)
. It says very little about evaluation order; a[i]
and i++
must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c
is parsed as (a + b) + c
(left-to-right) or as a + (b + c)
(right-to-left).
Precedence also controls parsing and tells you whether a + b * c
is parsed as (a + b) * c
(+
has higher precedence than *
) or as a + (b * c)
(*
has higher precedence than +
).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
answered 9 hours ago
AngewAngew
141k13 gold badges282 silver badges370 bronze badges
141k13 gold badges282 silver badges370 bronze badges
1
Associativity is not relevant tof()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation likea-b+c
where there could (based on precedence alone) be a choice between(a-b)+c
ora-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)
– Eric Postpischil
7 hours ago
add a comment |
1
Associativity is not relevant tof()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation likea-b+c
where there could (based on precedence alone) be a choice between(a-b)+c
ora-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)
– Eric Postpischil
7 hours ago
1
1
Associativity is not relevant to
f()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation like a-b+c
where there could (based on precedence alone) be a choice between (a-b)+c
or a-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)– Eric Postpischil
7 hours ago
Associativity is not relevant to
f()()()
. There is no other way to structure the expression, so there is no choice for associativity to resolve. Associativity applies in a situation like a-b+c
where there could (based on precedence alone) be a choice between (a-b)+c
or a-(b+c)
. (And the C rules actually specify expression structure or parsing by grammar, not by explicit precedence or associativity direction.)– Eric Postpischil
7 hours ago
add a comment |
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c
, a + (b + c)
, or (b + c) + a
.
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since *
has higher precedence than +
, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y
overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
add a comment |
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c
, a + (b + c)
, or (b + c) + a
.
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since *
has higher precedence than +
, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y
overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
add a comment |
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c
, a + (b + c)
, or (b + c) + a
.
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since *
has higher precedence than +
, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y
overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c
, a + (b + c)
, or (b + c) + a
.
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since *
has higher precedence than +
, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y
overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
edited 8 hours ago
answered 9 hours ago
BarmarBarmar
460k38 gold badges282 silver badges387 bronze badges
460k38 gold badges282 silver badges387 bronze badges
add a comment |
add a comment |
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the +
and -
operators have the same precedence level, so a + b
is first evaluated, then a + b - c
.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x
must be called first, then the function pointer returned by x
is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i
on the left side may be evaluated before or after the side effect of ++
. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
add a comment |
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the +
and -
operators have the same precedence level, so a + b
is first evaluated, then a + b - c
.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x
must be called first, then the function pointer returned by x
is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i
on the left side may be evaluated before or after the side effect of ++
. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
add a comment |
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the +
and -
operators have the same precedence level, so a + b
is first evaluated, then a + b - c
.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x
must be called first, then the function pointer returned by x
is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i
on the left side may be evaluated before or after the side effect of ++
. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the +
and -
operators have the same precedence level, so a + b
is first evaluated, then a + b - c
.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x
must be called first, then the function pointer returned by x
is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i
on the left side may be evaluated before or after the side effect of ++
. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
answered 9 hours ago
dbushdbush
111k15 gold badges124 silver badges157 bronze badges
111k15 gold badges124 silver badges157 bronze badges
add a comment |
add a comment |
- It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would apply to single calls like
f()
, or nested calls likef(g())
. It wouldn't say anything about two separate function calls on either side of a+
operator. - Precedence and associativity don't help us at all in the expression
a[i] = i++
. There simply is no rule that says precisely wheni++
stores the new result back intoi
, meaning that there is no rule to tell us whether thea[i]
part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c
, does the +
or the *
apply first? In *p++
, does the *
or the ++
apply first? Precedence answers these questions.
Associativity tells you what happens when you have a string of the same operators in a row. In a + b + c
, which +
applies first?
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f)
, there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
In a + b * c
precedence tells us that the multiplication happens before the addition, and in a + b + c
, associativity tells us that the left-hand addition happens before the right-hand one. But in f() + g() + x() * y()
there's nothing to tell us which order the function calls happen in, even though (once they've been called) precedence and associativity tell us in what order their return values will be multiplied and added together.
See also this answer which, although it's about a different question, explains the same points in more detail.
add a comment |
- It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would apply to single calls like
f()
, or nested calls likef(g())
. It wouldn't say anything about two separate function calls on either side of a+
operator. - Precedence and associativity don't help us at all in the expression
a[i] = i++
. There simply is no rule that says precisely wheni++
stores the new result back intoi
, meaning that there is no rule to tell us whether thea[i]
part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c
, does the +
or the *
apply first? In *p++
, does the *
or the ++
apply first? Precedence answers these questions.
Associativity tells you what happens when you have a string of the same operators in a row. In a + b + c
, which +
applies first?
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f)
, there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
In a + b * c
precedence tells us that the multiplication happens before the addition, and in a + b + c
, associativity tells us that the left-hand addition happens before the right-hand one. But in f() + g() + x() * y()
there's nothing to tell us which order the function calls happen in, even though (once they've been called) precedence and associativity tell us in what order their return values will be multiplied and added together.
See also this answer which, although it's about a different question, explains the same points in more detail.
add a comment |
- It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would apply to single calls like
f()
, or nested calls likef(g())
. It wouldn't say anything about two separate function calls on either side of a+
operator. - Precedence and associativity don't help us at all in the expression
a[i] = i++
. There simply is no rule that says precisely wheni++
stores the new result back intoi
, meaning that there is no rule to tell us whether thea[i]
part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c
, does the +
or the *
apply first? In *p++
, does the *
or the ++
apply first? Precedence answers these questions.
Associativity tells you what happens when you have a string of the same operators in a row. In a + b + c
, which +
applies first?
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f)
, there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
In a + b * c
precedence tells us that the multiplication happens before the addition, and in a + b + c
, associativity tells us that the left-hand addition happens before the right-hand one. But in f() + g() + x() * y()
there's nothing to tell us which order the function calls happen in, even though (once they've been called) precedence and associativity tell us in what order their return values will be multiplied and added together.
See also this answer which, although it's about a different question, explains the same points in more detail.
- It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would apply to single calls like
f()
, or nested calls likef(g())
. It wouldn't say anything about two separate function calls on either side of a+
operator. - Precedence and associativity don't help us at all in the expression
a[i] = i++
. There simply is no rule that says precisely wheni++
stores the new result back intoi
, meaning that there is no rule to tell us whether thea[i]
part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c
, does the +
or the *
apply first? In *p++
, does the *
or the ++
apply first? Precedence answers these questions.
Associativity tells you what happens when you have a string of the same operators in a row. In a + b + c
, which +
applies first?
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f)
, there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
In a + b * c
precedence tells us that the multiplication happens before the addition, and in a + b + c
, associativity tells us that the left-hand addition happens before the right-hand one. But in f() + g() + x() * y()
there's nothing to tell us which order the function calls happen in, even though (once they've been called) precedence and associativity tell us in what order their return values will be multiplied and added together.
See also this answer which, although it's about a different question, explains the same points in more detail.
edited 8 hours ago
answered 9 hours ago
Steve SummitSteve Summit
19.7k2 gold badges28 silver badges51 bronze badges
19.7k2 gold badges28 silver badges51 bronze badges
add a comment |
add a comment |
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z
. The additive operators +
and -
are left-associative, so that sequence is parsed as (x + y) - z
- IOW, the result of z
is subtracted from the result of x + y
.
THIS DOES NOT MEAN that any of x
, y
, or z
have to be evaluated in any particular order. It does not mean that x + y
must be evaluated before z
. It only means that the result of x + y
must be known before the result of z
is subtracted from it.
Regarding x = f() + g()
, all that matters is that the results of f()
and g()
are known before they can be added together - it does not mean that f()
must be evaluated before g()
. And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i]
and i++
are unsequenced with respect to each other). You cannot both update an object (i++
) and use its value in a computation (a[i]
) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++
(or a[i++] = i
) and x = x++
all have undefined behavior, and the result can be quite literally anything.
Note that the &&
, ||
, ?:
, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++
will be evaluated first and its side effect will be applied before a[i]
is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators +
and -
is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression
can produce a single multiplicative-expression
, or it can produce another additive-expression
followed by an additive operator followed by a multiplicative-expression
. Let's see how this plays out with x + y - z
:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y
is grouped together into an additive-expression
first, and then that expression is grouped with z
to form another additive-expression
.
add a comment |
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z
. The additive operators +
and -
are left-associative, so that sequence is parsed as (x + y) - z
- IOW, the result of z
is subtracted from the result of x + y
.
THIS DOES NOT MEAN that any of x
, y
, or z
have to be evaluated in any particular order. It does not mean that x + y
must be evaluated before z
. It only means that the result of x + y
must be known before the result of z
is subtracted from it.
Regarding x = f() + g()
, all that matters is that the results of f()
and g()
are known before they can be added together - it does not mean that f()
must be evaluated before g()
. And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i]
and i++
are unsequenced with respect to each other). You cannot both update an object (i++
) and use its value in a computation (a[i]
) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++
(or a[i++] = i
) and x = x++
all have undefined behavior, and the result can be quite literally anything.
Note that the &&
, ||
, ?:
, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++
will be evaluated first and its side effect will be applied before a[i]
is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators +
and -
is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression
can produce a single multiplicative-expression
, or it can produce another additive-expression
followed by an additive operator followed by a multiplicative-expression
. Let's see how this plays out with x + y - z
:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y
is grouped together into an additive-expression
first, and then that expression is grouped with z
to form another additive-expression
.
add a comment |
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z
. The additive operators +
and -
are left-associative, so that sequence is parsed as (x + y) - z
- IOW, the result of z
is subtracted from the result of x + y
.
THIS DOES NOT MEAN that any of x
, y
, or z
have to be evaluated in any particular order. It does not mean that x + y
must be evaluated before z
. It only means that the result of x + y
must be known before the result of z
is subtracted from it.
Regarding x = f() + g()
, all that matters is that the results of f()
and g()
are known before they can be added together - it does not mean that f()
must be evaluated before g()
. And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i]
and i++
are unsequenced with respect to each other). You cannot both update an object (i++
) and use its value in a computation (a[i]
) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++
(or a[i++] = i
) and x = x++
all have undefined behavior, and the result can be quite literally anything.
Note that the &&
, ||
, ?:
, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++
will be evaluated first and its side effect will be applied before a[i]
is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators +
and -
is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression
can produce a single multiplicative-expression
, or it can produce another additive-expression
followed by an additive operator followed by a multiplicative-expression
. Let's see how this plays out with x + y - z
:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y
is grouped together into an additive-expression
first, and then that expression is grouped with z
to form another additive-expression
.
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z
. The additive operators +
and -
are left-associative, so that sequence is parsed as (x + y) - z
- IOW, the result of z
is subtracted from the result of x + y
.
THIS DOES NOT MEAN that any of x
, y
, or z
have to be evaluated in any particular order. It does not mean that x + y
must be evaluated before z
. It only means that the result of x + y
must be known before the result of z
is subtracted from it.
Regarding x = f() + g()
, all that matters is that the results of f()
and g()
are known before they can be added together - it does not mean that f()
must be evaluated before g()
. And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i]
and i++
are unsequenced with respect to each other). You cannot both update an object (i++
) and use its value in a computation (a[i]
) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++
(or a[i++] = i
) and x = x++
all have undefined behavior, and the result can be quite literally anything.
Note that the &&
, ||
, ?:
, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++
will be evaluated first and its side effect will be applied before a[i]
is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators +
and -
is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression
can produce a single multiplicative-expression
, or it can produce another additive-expression
followed by an additive operator followed by a multiplicative-expression
. Let's see how this plays out with x + y - z
:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y
is grouped together into an additive-expression
first, and then that expression is grouped with z
to form another additive-expression
.
answered 7 hours ago
John BodeJohn Bode
87.4k15 gold badges87 silver badges155 bronze badges
87.4k15 gold badges87 silver badges155 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57484829%2fbeginner-in-need-of-a-simple-explanation-of-the-difference-between-order-of-eval%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Related: Why are these constructs using pre and post-increment undefined behavior?
– JL2210
9 hours ago
As a general rule, if there's no requirement that something has to happen, then the behaviour is termed "undefined" and anything can and will happen instead.
f()
andg()
will both be evaluated prior to the addition being performed. That much is assured, but as to the order, that doesn't matter and shouldn't impact your code. Same goes for arguments. When in doubt consult the C standard you're working with, whatever that is.– tadman
9 hours ago
stackoverflow.com/questions/5473107/…
– Mat
9 hours ago