简体   繁体   中英

In C/C++ arithmetic operation inside of for statement arguments

Let's say I have this code:

int v;
setV(&v);
for (int i = 0; i < v - 5; i++) {
  // Do stuff here, but don't use v.
}

Will the operation v - 5 be run every time or will a modern compiler be smart enough to store it once and never run it again?

What if I did this:

int v;
setV(&v);
const int cv = v;
for (int i = 0; i < cv - 5; i++) {
  // Do stuff here. Changing cv is actually impossible.
}

Would the second style make a difference?

Edit:

This was an interesting question for an unexpected reason. It's more a question of the compiler avoiding the obtuse case of an unintended aliasing of v . If the compiler can prove that this won't happen (version 2) then we get better code.

The lesson here is to be more concerned with eliminating aliasing than trying to do the optimiser's job for it.

Making the copy cv actually presented the biggest optimisation (elision of redundant memory fetches), even though at a first glance it would appear to be (slightly) less efficient.

original answer and demo:

Let's see:

given:

extern void setV(int*);
extern void do_something(int i);

void test1()
{
    int v;
    setV(&v);
    for (int i = 0; i < v - 5; i++) {
    // Do stuff here, but don't use v.
      do_something(i);
    }
}


void test2()
{
    int v;
    setV(&v);
    const int cv = v;
    for (int i = 0; i < cv - 5; i++) {
      // Do stuff here. Changing cv is actually impossible.
      do_something(i);
    }  
}

compile on gcc5.3 with -x c++ -std=c++14 -O2 -Wall

gives:

test1():
        pushq   %rbx
        subq    $16, %rsp
        leaq    12(%rsp), %rdi
        call    setV(int*)
        cmpl    $5, 12(%rsp)
        jle     .L1
        xorl    %ebx, %ebx
.L5:
        movl    %ebx, %edi
        addl    $1, %ebx
        call    do_something(int)
        movl    12(%rsp), %eax
        subl    $5, %eax
        cmpl    %ebx, %eax
        jg      .L5
.L1:
        addq    $16, %rsp
        popq    %rbx
        ret
test2():
        pushq   %rbp
        pushq   %rbx
        subq    $24, %rsp
        leaq    12(%rsp), %rdi
        call    setV(int*)
        movl    12(%rsp), %eax
        cmpl    $5, %eax
        jle     .L8
        leal    -5(%rax), %ebp
        xorl    %ebx, %ebx
.L12:
        movl    %ebx, %edi
        addl    $1, %ebx
        call    do_something(int)
        cmpl    %ebp, %ebx
        jne     .L12
.L8:
        addq    $24, %rsp
        popq    %rbx
        popq    %rbp
        ret

The second form is better on this compiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM