Reputation: 305
This was an interview question. I said they were the same, but this was adjudged an incorrect response. From the assembler point of view, is there any imaginable difference? I have compiled two short C programs using default gcc optimization and -S to see the assembler output, and they are the same.
Upvotes: 17
Views: 9260
Reputation: 21366
"What is the difference between ++i and i=i+1 from an assembler point of view?" is not a well-defined question. My suspicion is that the interviewer's question was more like "What is the difference between ++i and i=i+1?" but that the OP added "from an assembler point of view" believing that the generated assembly code is the final word on the matter.
Maybe this is a charitable interpretation, but I would imagine that the interviewer wanted to know if the OP knew the difference in the semantics of ++i
vs. i=i+1
. The short answer is: the Standard guarantees that the argument of ++i
will be evaluated once only, but there is no such guarantee for i=i+1
: it is possible that the argument i
will be evaluated twice in this second expression.
Of course, in the end the generated assembly is what matters, but the C language specifies semantics so that you don't always need to check assembly to see if code does what you think it should do; you just need to code to the Standard. It's great to be able to inspect the assembly to verify that code generation is good, but that doesn't tell you how code will be generated, e.g., on another platform, or using a different version of the same compiler. Better to know what the language guarantees are first.
i=i+1
is a simple assignment. The Standard says of assignment that (C11 6.5.16p3):
An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion. 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.
This is a description of the semantics of assignment. The expression on the left side of the =
operator, i
, is evaluated, and the expression on the right side of the =
operator, i+1
is evaluated (in no particular order), then the value of i
is updated and the assignment expression takes the new value of i
. From the point of view of the program semantics there are two evaluations of i
. i
is evaluated with the right hand operand of the assignment operator, the expression i+1
. i
is also evaluated as the left hand operand of =
. This evaluation of the left hand operand precedes the update to i
, and its purpose is to determine the identity of the object to be updated (C11 5.1.2.3p2):
Evaluation of an expression in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.
This does not mean that an implementation is required to evaluate i
twice. An implementation may perform optimizations so long as the resulting program has the same observable behavior as the program would have under the abstract semantics.
On the other hand, the prefix expression ++i
is equivalent to the compound assignment expression i+=1
. The semantics of this compound assignment expression are described as (C11 6.5.16.2p3):
A compound assignment of the form E1 op = E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once, and with respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation. If E1 has an atomic type, compound assignment is a read-modify-write operation with memory_order_seq_cst memory order semantics.
If I were answering the interviewer I would say something like this:
The C Standard guarantees that
i
will be evaluated one time only in the expression++i
, or in the equivalent expressioni+=1
. There is no guarantee against multiple evaluations ofi
in the expressioni=i+1
, although it is likely that compiler optimizations will result in code that is equivalent to the preincrement form in this respect.
For bonus points I might add that:
If the code is compiled under C11 or later and if
i
is an atomic type,++i
andi+=1
are atomic operations, buti=i+1
is not atomic.
Upvotes: 1
Reputation: 21
the context is the main thing here because on a optimized release build the compiler will optimize away the i++ if its available to a simple [inc eax]. whereas something like int some_int = i++ would need to store the i value in some_int FIRST and only then increment i.
Upvotes: 0
Reputation: 49199
To defend the interviewer, context is everything. What is the type of i? Are we talking C or C++ (or some other C like language)? Were you given:
++i;
i = i + 1;
or was there more context?
If I had been asked this, my first response would've been "is i volatile?" If the answer is yes, then the difference is huge. If not, the difference is small and semantic, but pragmatically none. The proof of that is the difference in parse tree, and the ultimate meaning of the subtrees generated.
So it sounds like you got the pragmatic side right, but the semantic/critical thought side wrong.
To attack the interviewer (without context), I'd have to wonder what the purpose of the question was. If I asked the question, I'd want to use it to find out if the candidate knew subtle semantic differences, how to generate a parse tree, how to think critically and so on and so forth. I typically ask a C question of my interviewees that nearly every candidate gets wrong - and that's by design. I actually don't care about the answer to the question, I care about the journey that I will be taking with the candidate to reach understanding, which tells me far more about than right/wrong on a trivia question.
Upvotes: 7
Reputation: 82545
The interviewer may have wanted an answer something like this:
i=i+1
will have to load the value ofi
, add one to it, and then store the result back toi
. In contrast,++i
may simply increment the value using a single assembly instruction, so in theory it could be more efficient. However, most compilers will optimize away the difference, and the generated code will be exactly the same.
FWIW, the fact that you know how to look at assembly makes you a better programmer than 90% of the people I've had to interview over the years. Take solace in the fact that you won't have to work with the clueless loser who interviewed you.
Upvotes: 21
Reputation: 25759
In C++, it depends if i
is an int or an object. If it's an object, it would probably generate a temporary instance.
Upvotes: 3
Reputation: 625247
You are probably right. A naive compiler might do:
++i to inc [ax]
and
i = i + 1 to add [ax], 1
but any half sensible compiler will just optimize adding 1 to the first version.
This all assumes the relevant architecture has inc and add instructions (like x86 does).
Upvotes: 8
Reputation: 120498
Looks like you were right and they were wrong. I had a similar issue in a job interview, where I gave the correct answer that was deemed incorrect.
I confidently argued the point with my interviewer, who obviously took offence to my impudence. I didn't get the job, but then again, working under someone who "knows everything" wouldn't be that desirable either.
Upvotes: 10