If I do one of the following (which I assume are equivalent for the purpose of this question)
for(int i=0; i<A; i++)
{
//... do stuff
for(int j=0; j<B; j++)
{
//... do stuff
}
//... do stuff
}
for(int i=0; i<A; i++)
{
int j;
//... do stuff
}
Does the variable j
get recreated on the stack every loop (is the SP
constantly being updated every loop), or is the compiler smart enough to know how many local variables a function might have at one time, and then makes room for all of them on the stack at function entry?
I understand that this is theoretically compiler-dependent, but I assume simple things like this are common across all major compilers. If not, does someone know specifically about GCC
and VC++
compilers?
This is excellent practice. By creating variables inside loops, you ensure their scope is restricted to inside the loop. It cannot be referenced nor called outside of the loop.
It's not a problem to define a variable within a loop. In fact, it's good practice, since identifiers should be confined to the smallest possible scope. What's bad is to assign a variable within a loop if you could just as well assign it once before the loop runs.
If the variable is declared outside the loop, then it has the global scope as it can be used through-out the function and inside of the loop too. If the variable is declared inside the loop, then the scope is only valid inside the loop and if used outside the loop will give an error.
Often the variable that controls a for loop is needed only for the purposes of the loop and is not used elsewhere. When this is the case, it is possible to declare the variable inside the initialization portion of the for.
It is efficient. gcc
will optimize that, like most of the modern compilers. Also keep in mind what Donald Knuth said:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
You can check that it is efficient by comparing assembly code. Use for example diff
to do the comparison. To generate assembly use -S
flag, gcc -S
. It is equivalent to gcc -S -O0
, because default optimization level is 0. So, even on the lowest level optimizaton, gcc
will take care of this variable for you.
First version (for better readability prefer this way):
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
printf("%d ", i + j);
}
}
return 0;
}
Second version:
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
{
int j;
for (j = 0; j < 10; j++)
{
printf("%d ", i + j);
}
}
return 0;
}
Identical assembly result:
.file "main.cpp"
.section .rodata
.LC0:
.string "%d "
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -4(%rbp)
jmp .L2
.L5:
movl $0, -8(%rbp)
jmp .L3
.L4:
movl -8(%rbp), %eax
movl -4(%rbp), %edx
leal (%rdx,%rax), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
addl $1, -8(%rbp)
.L3:
cmpl $9, -8(%rbp)
setle %al
testb %al, %al
jne .L4
addl $1, -4(%rbp)
.L2:
cmpl $9, -4(%rbp)
setle %al
testb %al, %al
jne .L5
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits
int i
is -4(%rbp)
, int j
is -8(%rbp)
. As you can see int j
is not reallocated or something.
I believe the variables will only be created once, although I do not care and I don't believe you should either.
This is likely an example of pre-optimization (or unnecessary optimization) on your part; the potential inefficiency created by declaring variables within a loop is incredibly small and "optimizing" your code by declaring variables in different locations will have a negligible impact on the overall runtime and memory usage of your program.
Consider spending time optimizing your algorithms and finding efficient data structures, as this will likely be a much better use of your time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With