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?
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.