可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
Difference between declaring variables before or in loop?
24 answers
I am just wondering if there would be any loss of speed or efficiency if you did something like this:
int i = 0;
while(i < 100)
{
int var = 4;
i++;
}
which declares int var
one hundred times. It seems to me like there would be, but I\'m not sure. would it be more practical/faster to do this instead:
int i = 0;
int var;
while(i < 100)
{
var = 4;
i++;
}
or are they the same, speedwise and efficiency-wise?
回答1:
Stack space for local variables is usually allocated in function scope. So no stack pointer adjustment happens inside the loop, just assigning 4 to var
. Therefore these two snippets have the same overhead.
回答2:
For primitive types and POD types, it makes no difference. The compiler will allocate the stack space for the variable at the beginning of the function and deallocate it when the function returns in both cases.
For non-POD class types that have non-trivial constructors, it WILL make a difference -- in that case, putting the variable outside the loop will only call the constructor and destructor once and the assignment operator each iteration, whereas putting it inside the loop will call the constructor and destructor for every iteration of the loop. Depending on what the class\' constructor, destructor, and assignment operator do, this may or may not be desirable.
回答3:
They are both the same, and here\'s how you can find out, by looking at what the compiler does (even without optimisation set to high):
Look at what the compiler (gcc 4.0) does to your simple examples:
1.c:
main(){ int var; while(int i < 100) { var = 4; } }
gcc -S 1.c
1.s:
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $0, -16(%ebp)
jmp L2
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
leave
ret
2.c
main() { while(int i < 100) { int var = 4; } }
gcc -S 2.c
2.s:
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $0, -16(%ebp)
jmp L2
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
leave
ret
From these, you can see two things: firstly, the code is the same in both.
Secondly, the storage for var is allocated outside the loop:
subl $24, %esp
And finally the only thing in the loop is the assignment and condition check:
L3:
movl $4, -12(%ebp)
L2:
cmpl $99, -16(%ebp)
jle L3
Which is about as efficient as you can be without removing the loop entirely.
回答4:
These days it is better to declare it inside the loop unless it is a constant as the compiler will be able to better optimize the code (reducing variable scope).
EDIT: This answer is mostly obsolete now. With the rise of post-classical compilers, the cases where the compiler can\'t figure it out are getting rare. I can still construct them but most people would classify the construction as bad code.
回答5:
Most modern compilers will optimize this for you. That being said I would use your first example as I find it more readable.
回答6:
For a built-in type there will likely be no difference between the 2 styles (probably right down to the generated code).
However, if the variable is a class with a non-trivial constructor/destructor there could well be a major difference in runtime cost. I\'d generally scope the variable to inside the loop (to keep the scope as small as possible), but if that turns out to have a perf impact I\'d look to moving the class variable outside the loop\'s scope. However, doing that needs some additional analysis as the semantics of the ode path may change, so this can only be done if the sematics permit it.
An RAII class might need this behavior. For example, a class that manages file access lifetime might need to be created and destroyed on each loop iteration to manage the file access properly.
Suppose you have a LockMgr
class that acquires a critical section when it\'s constructed and releases it when destroyed:
while (i< 100) {
LockMgr lock( myCriticalSection); // acquires a critical section at start of
// each loop iteration
// do stuff...
} // critical section is released at end of each loop iteration
is quite different from:
LockMgr lock( myCriticalSection);
while (i< 100) {
// do stuff...
}
回答7:
Both loops have the same efficiency. They will both take an infinite amount of time :) It may be a good idea to increment i inside the loops.
回答8:
I once ran some perfomance tests, and to my surprise, found that case 1 was actually faster! I suppose this may be because declaring the variable inside the loop reduces its scope, so it gets free\'d earlier. However, that was a long time ago, on a very old compiler. Im sure modern compilers do a better job of optimizing away the diferences, but it still doesn\'t hurt to keep your variable scope as short as possible.
回答9:
#include <stdio.h>
int main()
{
for(int i = 0; i < 10; i++)
{
int test;
if(i == 0)
test = 100;
printf(\"%d\\n\", test);
}
}
Code above always prints 100 10 times which means local variable inside loop is only allocated once per each function call.
回答10:
The only way to be sure is to time them. But the difference, if there is one, will be microscopic, so you will need a mighty big timing loop.
More to the point, the first one is better style because it initializes the variable var, while the other one leaves it uninitialized. This and the guideline that one should define variables as near to their point of use as possible, means that the first form should normally be preferred.
回答11:
With only two variables, the compiler will likely be assign a register for both. These registers are there anyway, so this doesn\'t take time. There are 2 register write and one register read instruction in either case.
回答12:
I think that most answers are missing a major point to consider which is: \"Is it clear\" and obviously by all the discussion the fact is; no it is not.
I\'d suggest in most loop code the efficiency is pretty much a non-issue (unless you calculating for a mars lander), so really the only question is what looks more sensible and readable & maintainable - in this case I\'d recommend declaring the variable up front & outside the loop - this simply makes it clearer. Then people like you & I would not even bother to waste time checking online to see if it\'s valid or not.
回答13:
thats not true
there is overhead however its neglect able overhead.
Even though probably they will end up at same place on stack It still assigns it.
It will assign memory location on stack for that int and then free it at the end of }. Not in heap free sense in sense it will move sp (stack pointer) by 1.
And in your case considering it only has one local variable it will just simply equate fp(frame pointer) and sp
Short answer would be: DONT CARE EITHER WAY WORKS ALMOST THE SAME.
But try reading more on how stack is organized. My undergrad school had pretty good lectures on that
If you wanna read more check here
http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Assembler1/lecture.html