3

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.

  • 8
    Likely no difference at all. – Fred Larson Dec 08 '20 at 22:22
  • 4
    Don't sweat the small stuff. This is really small stuff. – R Sahu Dec 08 '20 at 22:25
  • 3
    Print out the assembly language. The truth is in the assembly language. – Thomas Matthews Dec 08 '20 at 22:33
  • Note that everyone is making assumption that `i` and `j` are a primitive datatype like an `int`, not something with complex initialization and assignment logic. – user4581301 Dec 08 '20 at 23:08
  • 1
    @user4581301 - `i` and `j`, in a lot of subjects (math, computer science, programming) conventionally denote integral values, unless otherwise stated. – Peter Dec 09 '20 at 01:14
  • For the OP - read up on "premature optimization", because that is exactly what you are doing. As comments have already noted, you're sweating the small stuff. In most realistic use cases where `i` and `j` are of type `int` (default assumption, since you haven't specified) modern compilers will easily produce the most efficient code in both cases. Focus your attention on ensuring HUMANS can comprehend your code, since HUMANS are more likely to alter and break code they do not understand. Then - and only if TESTING shows the difference even matters - worry about insignificant tweaks like this. – Peter Dec 09 '20 at 01:22
  • Thank you all for a lot of feedback. – Bartłomiej Sitnik Dec 10 '20 at 09:16
  • 1
    Please see: https://stackoverflow.com/help/someone-answers – mkrieger1 Dec 10 '20 at 09:18

4 Answers4

4

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.

founderio
  • 407
  • 1
  • 3
  • 15
4

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.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
0

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
3.141592
  • 96
  • 8
-1

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.

Florent
  • 436
  • 3
  • 8