Which is faster?

If we have the following 2 code fragments in C ++ that perform the same task:

int a, b=somenumber; while(b > 0) { a = b % 3; b /= 3; } 

or

 int b=somenumber; while(b > 0) { int a=b%3; b /= 3; } 

I don't know much about computer / C ++ architecture, but I think the first code is faster because it declares an integer a at the beginning and just uses it in a while loop, and in the second code, an integer a is declared every time the loop while begins. Can someone help me with this, am I right, what and why?

+7
c ++ design
source share
8 answers

An int declaration is information for the compiler and does not translate into an instruction that must be encoded. So it does not matter. An int declaration inside the loop will not overlap the loop. Why not try compiling both for yourself and get the compiler to output assembly code so you can see for yourself.

+11
source share

There should not be any difference, but be an additional empirical (anal?) I tested this with g ++, creating a function for each of the code snippets. With and without optimization, it generated identical code no matter where the int a declaration is located.

 #include <iostream> int variant_a(int b) { int a; while(b > 0) { a = b % 3; b /= 3; } return b; } int variant_b(int b) { while(b > 0) { int a = b % 3; b /= 3; } return b; } int main() { std::cout << variant_a(42) << std::endl; std::cout << variant_b(42) << std::endl; } 

This is an unoptimized loop:

 _Z9variant_ai: .LFB952: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: subl $24, %esp .LCFI2: jmp .L2 .L3: movl 8(%ebp), %eax movl %eax, -20(%ebp) movl $1431655766, -24(%ebp) movl -24(%ebp), %eax imull -20(%ebp) movl %edx, %ecx movl -20(%ebp), %eax sarl $31, %eax subl %eax, %ecx movl %ecx, %eax addl %eax, %eax addl %ecx, %eax movl -20(%ebp), %edx subl %eax, %edx movl %edx, %eax movl %eax, -4(%ebp) movl 8(%ebp), %eax movl %eax, -20(%ebp) movl $1431655766, -24(%ebp) movl -24(%ebp), %eax imull -20(%ebp) movl %edx, %ecx movl -20(%ebp), %eax sarl $31, %eax movl %ecx, %edx subl %eax, %edx movl %edx, %eax movl %eax, 8(%ebp) .L2: cmpl $0, 8(%ebp) jg .L3 movl 8(%ebp), %eax leave ret 

and optimized:

 _Z9variant_ai: .LFB968: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: pushl %ebx .LCFI2: movl 8(%ebp), %ebx testl %ebx, %ebx jle .L2 movl $1431655766, %ecx .p2align 4,,7 .p2align 3 .L5: movl %ebx, %eax imull %ecx movl %ebx, %eax sarl $31, %eax movl %edx, %ebx subl %eax, %ebx jne .L5 .L2: movl %ebx, %eax popl %ebx popl %ebp ret 
+14
source share
Seriously, does it really matter? These are the type of micro optimizations you should avoid. Write a code that is more readable, and IMHO is the second. The compiler is good enough to do optimizations for these types of things, and I would leave that for that.
+5
source share

There is no "faster" in the C ++ standard, with the exception of performance guarantees in the standard library. The optimizing compiler will most likely exclude a because it is not used. Alternatively, he could allocate all the memory needed for all local variables at once, and then that would also have no meaning.

The only legitimate question about low-level language constructs like this is whether your particular implementation is running faster or slower, and the best way to find out is by yourself. You will find that many of these things simply do not matter, and if you study the generated code, you will often find that compilers do the same with different ways of writing code.

Usually looking for micro-optimizations is a bad idea, but if you are trying to customize the overall style, this can be useful (for example, using ++i rather than i++ ). However, if you are customizing your style for any purpose other than reading, you must have good reason for this. In this case, this means performance testing.

+2
source share

No, it cannot be "declared" in a loop, because it is declared at compile time. I would say that they are equal, but the second may have been faster if the type of the variable was something more complex, having a constructor and destructor.

+1
source share

Theoretically, the first option could be faster. In practice, I would expect a and b to be placed in registers so that the generated assembly is identical (which you can check in the compiled binary). If you run enough time, which, in your opinion, may be the difference, the only way to know is to measure. If your profiler cannot distinguish from each other, program it so that the code is the clearest for future maintainers.

In general (as already mentioned) these types of optimizations will not provide any significant improvement in program performance. Instead, you should look for algorithmic and design optimizations.

+1
source share

I do not believe that in practice there will be any difference. There are no memory allocations since memory for automatic variables is allocated or deferred at compile time.

Theoretically, I think the second can be faster and faster: the compiler has more information about where and how the variables are used (for example, you can reuse the same variable for something completely unrelated later).

You can start to worry about such things when dealing with types that are expensive to build. For example, you should declare std :: vector in the inner loop or declare it before the loop and clear() at the beginning of the loop body (reuse of allocated memory).

0
source share

The first should be faster; however, the compiler is usually smart enough to optimize it on its own, so it probably doesn't matter.

For the sake of purity, the answer is first

EDIT: it's faster because it only needs one distribution, not N (N is the number of iterations performed by the while loop).

-6
source share

All Articles