使用const参数将参数传递给函数:它更快吗?

bec*_*cko 21 c const function-parameter

例如,考虑一下:

int sum(int a, int b)
{
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

int sum(const int a, const int b)
{
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

第二种方法通常更快吗?

C中的函数参数被复制并发送到函数,因此函数内部的更改不会影响原始值.我的理由是,在sum上面的第二个中,编译器确实知道a并且b没有在函数内部进行修改,所以它只能传递原始值而不先复制它们.这就是为什么我认为第二个sum比第一个更快.但我真的不知道.在sum上面特别简单的例子中,差异(如果有的话)应该是最小的.

编辑:这个sum例子只是为了说明我的观点.我不希望在这个特定的例子中应该有很大的差异.但我想知道在更复杂的情况下const,编译器是否可以利用函数参数中的修饰符来使函数更快.我怀疑编译器总能确定一个参数是否在一个函数内被改变(因此我的第二个问题在下面); 因此我希望当它找到一个const修饰符时,它会做出与没有const修饰符时不同的东西.

问题:一般来说,一个函数在它的参数时会const比它们不是时更快?

问题2:通常,C编译器(理论上)是否总能确定函数内是否更改了函数参数?

Ric*_*III 16

简答:不

答案很长,不,有证据.

在我使用clang编译的MacBook pro上,我运行了几次这个测试,看到没有实际时间差异:

int add(int a, int b)
{
    return a + b;
}

const int cadd(const int a, const int b)
{
    return a + b;
}

int main (int argc, char * argv[])
{
#define ITERS 1000000000

    clock_t start = clock();
    int j = 0;
    for (int i = 0; i < ITERS; i++)
    {
        j += add(i, i + 1);
    }

    printf("add took %li ticks\n", clock() - start);

    start = clock();
    j = 0;
    for (int i = 0; i < ITERS; i++)
    {
        j += cadd(i, i + 1);
    }

    printf("cadd took %li ticks\n", clock() - start);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

产量

add took 4875711 ticks
cadd took 4885519 ticks

然而,这些时间确实应该花费一些时间,因为clock它不是最精确的计时功能,并且可能受到其他正在运行的程序的影响.

那么,这是生成的比较汇编:

_add:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %esi
    addl    -8(%rbp), %esi
    movl    %esi, %eax
    popq    %rbp
    ret

_cadd:                                 
    .cfi_startproc    
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %esi
    addl    -8(%rbp), %esi
    movl    %esi, %eax
    popq    %rb
Run Code Online (Sandbox Code Playgroud)

所以,正如你所看到的,两者之间没有区别.传递参数const只是对调用者的一个提示,参数不会被改变,并且在如上所述的简单场景中,不会导致编译任何不同的汇编.

  • 我不认为这是一个"证据".当然,它证明了它适用于您的特定体系结构,编译器和优化设置,但OP的问题是关于C的一般问题.此外,您没有告诉我们您正在使用的体系结构,编译器和优化设置. (19认同)
  • @ RichardJ.RossIII +1,但你正在使用`no optimization`.我想看看如果让编译器进行"优化"会发生什么. (3认同)
  • @ RichardJ.RossIII可以仅禁用内联,但保留所有其他优化吗?我的问题的关键是const函数参数是否允许编译器进行更多的优化。 (2认同)

Dav*_*son 9

答案可能取决于您的编译器,优化级别以及编译器是否决定内联函数.如果您对这些事情感到好奇,可以很容易地看一下编译器生成的实际汇编并找出答案.