i=j=0; or i=0; j=0; which is more efficient?

Viewed 182

I'm new to programming (just after my first year of using C++ with addition of some other languages. I've come across a small dillema. Which of these codes is better? Even if only just a little.

i = j = 0;

And second solution

i = 0;
j = 0;

I'm using it in a 'for' loop. That's why this is important for me to know.

4 Answers

With modern compilers, these will not make a difference.

See here for a read-up on common compiler optimizations: https://queue.acm.org/detail.cfm?id=3372264

However, as @asteroids-with-wings rightly points out, these don't even come into play here.

What actually happens is very likely to be compiler-specific, but you can check what they create by looking at the assembly code.

Example code:

test.cpp:

int main(int argc, char **argv) {
    int i, j;

    i = j = 0;
}

test2.cpp:

int main(int argc, char **argv) {
    int i, j;

    i = 0;
    j = 0;
}

I compiled them with the following options:

clang test.cpp -O0 -save-temps=obj -o test_exec
clang test2.cpp -O0 -save-temps=obj -o test_exec2

-O0 is to disable optimizations, -save-temps=obj will keep the generated assembly around for inspection.

This provides the following two assembly files:

test.s:

    .text
    .file   "test.cpp"
    .globl  main                            # -- Begin function main
    .p2align    4, 0x90
    .type   main,@function
main:                                   # @main
    .cfi_startproc
# %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    xorl    %eax, %eax
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movl    $0, -24(%rbp)
    movl    $0, -20(%rbp)
    popq    %rbp
    .cfi_def_cfa %rsp, 8
    retq
.Lfunc_end0:
    .size   main, .Lfunc_end0-main
    .cfi_endproc
                                        # -- End function
    .ident  "clang version 11.0.0"
    .section    ".note.GNU-stack","",@progbits
    .addrsig

test2.s:

    .text
    .file   "test2.cpp"
    .globl  main                            # -- Begin function main
    .p2align    4, 0x90
    .type   main,@function
main:                                   # @main
    .cfi_startproc
# %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    xorl    %eax, %eax
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    movl    $0, -20(%rbp)
    movl    $0, -24(%rbp)
    popq    %rbp
    .cfi_def_cfa %rsp, 8
    retq
.Lfunc_end0:
    .size   main, .Lfunc_end0-main
    .cfi_endproc
                                        # -- End function
    .ident  "clang version 11.0.0"
    .section    ".note.GNU-stack","",@progbits
    .addrsig

As you can see in the diff:

2c2
<   .file   "test.cpp"
---
>   .file   "test2.cpp"
17d16
<   movl    $0, -24(%rbp)
18a18
>   movl    $0, -24(%rbp)

there is very little difference between the two codes.

The only real difference is in lines 17 + 18, where these two lines are swapped:

movl    $0, -20(%rbp)
movl    $0, -24(%rbp)

Even without optimization, the only difference here is the order in which the variables are initialized, otherwise the same thing happens.

Note: this holds true for your specific case of assigning a compile-time constant (0). Results may differ for using run-time values from other variables. As always in performance questions: Investigate what your compiler does, and profile the result - there may not be a single true answer.

These pieces of code literally describe the same program. There is no difference between them beyond syntax.

Thus, there will be no performance difference at runtime.

Remember, your C++ code is a description of a program, not a sequence of instructions for a computer to perform. It's your compiler's job to create one of those, after reading and understanding your source code.

It depends!

Your compiler should be smart enough to handle that and in the end is able to produce the same assembler instructions from that! To see what's going on you can use the assembler output of your compiler. for GCC that means using the '-S' option.

g++ -S assignment_efficiency.cpp

if you run that command with two different versions, you'll eventually find out that the 'separate variant' will result in one asm command less than the 'combined variant', thus you could name it 'more efficient' to some extend.

BUT

if you tell your compiler to optimize, using the -O option, you'll get the exact same asm instructions.

g++ -S -O3 assignment_efficiency.cpp 

you can verify that by saving both variants to a separate file and run a diff on them. e.g.

diff single.s sep.s
diff single.o3.s sep.o3.s

Compilers try to optimize producted code.

So It probably depends on compiler.

There are ways to know like generating asm and read the output code.

for getting asm :

How do you get assembler output from C/C++ source in gcc?

and other way is to see the duration of a big loop with compiler.

Related