23

Consider, for example:

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

vs.

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

Is the second approach in general faster?

Function parameters in C are copied and sent to the function, so that changes inside the function do not affect the original values. My reasoning is that in the second sum above, the compiler knows for sure that a and b are not modified inside the function, so it can just pass the original values without copying them first. That's why I think the second sum is faster than the first. But I don't really know. In the particular simple example of sum above, the differences, if any, should be minimal.

Edit: The sum example is just to illustrate my point. I don't expect that in this particular example there should be large differences. But I wonder if in more complicated situations the const modifier inside a function parameter can be exploited by the compiler to make the function faster. I doubt that the compiler can always determine whether a parameter is changed inside a function (hence my 2nd question below); hence I'd expect that when it finds a const modifier, it does something different than when there's no const modifier.

Question: In general, a function will be faster when its arguments are const, than when they are not?

Question 2: In general, can a C compiler (theoretically) always determine whether a function parameter is changed inside the function?

Claudio Cortese
  • 1,287
  • 1
  • 11
  • 21
becko
  • 13,246
  • 24
  • 74
  • 144
  • 1
    The compiler, however, knows very well `a` and `b` are left unmodified in both versions, so whatever optimizations it could apply... – eq- Sep 06 '12 at 00:53
  • 4
    Look at the generated assembly to see if there's any difference. (There probably isn't). – Blastfurnace Sep 06 '12 at 00:54
  • @Blastfurnace gcc 4.5.2 generates exact same assembly codes. – shinkou Sep 06 '12 at 00:58
  • @Blastfurnace: +1. And of course, don't forget to test it with optimizations flags. Probably, by using `const` will be written on read-only memory, which normally is faster. – Jack Sep 06 '12 at 01:04
  • @Blastfurnace +1 Good idea. I'll try it. – becko Sep 07 '12 at 02:07

4 Answers4

16

Short answer: No

Long answer, no, with proof.

I ran this test, a couple of times, and saw no real time difference, on my MacBook pro compiled with clang:

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;
}

Output

add took 4875711 ticks
cadd took 4885519 ticks

These times really should be taken with a grain of salt, however, as clock isn't the most accurate of timing functions, and can be influenced by other running programs.

So, here is the compared assembly generated:

_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

So, as you can see, there is No difference between the two. Passing an argument as const is only a hint to the caller the the argument will not be changed, and in a simple scenario like the one described above, will not result in any different assembly compiled.

Richard J. Ross III
  • 53,315
  • 24
  • 127
  • 192
  • 20
    I would not consider this to be a "proof". Sure, it proves it for your particular architecture, compiler, and optimization settings, but the OP's question is a general one about C. Also, you didn't tell us what architecture, compiler, and optimization settings you are using. – David Grayson Sep 07 '12 at 00:03
  • @DavidGrayson I'm using a macbook pro, so It's 64bit, clang, and no optimization (-O0). – Richard J. Ross III Sep 07 '12 at 00:22
  • 4
    @RichardJ.RossIII +1, But you are using `no optimization`. I would like to see what happens if you let the compiler do `optimization`. – becko Sep 07 '12 at 02:04
  • @becko I'd assume that it would inline the functions, which makes the test moot. – Richard J. Ross III Sep 07 '12 at 14:31
  • 2
    @RichardJ.RossIII Could one disable only inlining, but retain all other optimizations? The point of my question is whether `const` function arguments allow the compiler to do more **optimizations**. – becko Sep 08 '12 at 20:37
  • @becko I doubt it, unless you are dealing with pointers, the addresses of `a` and `b` are always going to be different, so there is no need to reload registers in that scenario. I will perform some more tests tomorrow, It's late right now :) – Richard J. Ross III Sep 09 '12 at 02:06
9

The answer probably depends on your compiler, the optimization level, and whether the compiler decides to inline the function. If you are curious about these things, it is easy to just look at the actual assembly produced by your compiler and find out.

David Grayson
  • 71,301
  • 23
  • 136
  • 171
  • It probably depends on whether the function is static or not too; the compiler has more freedom to change/inline a static function because it knows it will not be called from other files. – David Grayson Sep 06 '12 at 01:29
  • +1 I am using Visual Studio 2010. I'll try to look at the assembly code generated, as suggested by @Blastfurnace, and see if there's any difference. – becko Sep 07 '12 at 02:08
  • 1
    Please, avoid terms like "it is easy to" as it can actually be for some but not for others. An octopus finds it easy to open 2 cans at the same time but I don't. Moreover, getting the disassembled code can be tricky with some development environments. – Chucky Aug 14 '17 at 15:44
0

No. both of them should be same speed. for your reason, assume it passes the original values in to sum function, how about some code out of the sum function modify the original value, for example, another thread.

In general, the const has no impact the performance at arguments. it do impact the performance if the const is a local/global variable because some calculation can be moved to compiling time as if it is a const.

RolandXu
  • 3,098
  • 2
  • 12
  • 20
0

Although late to the party, a compiler could put variables defined as const in a read-only memory segment/block, so that if an attempt was made to write to the address, via some pointer tomfoolery, the write to the memory would trigger an exception at runtime.

-- Jamey

Jamey Kirby
  • 113
  • 2
  • 6
  • 1
    This check happens at compile-time, not runtime. A runtime memory-write prohibition would require extra assembly and time that the compiler will not add. – Ethan T Jul 25 '17 at 02:08
  • 1
    @Jamey Kirby, this is true of variables, but not of function arguments. – Ant_222 May 19 '18 at 10:06
  • 1. By default the arguments are located in the stack. 2. the cosnt keyword do not change the location! – ivand58 Aug 08 '18 at 10:38