compare
is called from main()
without any parameters being passed.
No. It is just referred to from main
.
Essentially, it tells lfind
"Hey, if you want to compare entries, take this function - it can be called exactly the way you expect it."
lfind
, then, knows about that and whenever it needs to compare two entries, it puts the arguments wherever it would put them on a normal call (on the stack, into the right registers or wherever, depending on the calling conventions of the architecture) and performs the call to the given address. This is called an indirect call and is usually a bit more expensive than a direct call.
Let's switch to a simpler example:
#include <stdio.h>
int add1(int x) {
return x + 1;
}
int times2(int x) {
return x * 2;
}
int indirect42(int(*f)(int)) {
// Call the function we are passed with 42 and return the result.
return f(42);
}
int indirect0(int(*f)(int)) {
// Call the function we are passed with 0 and return the result.
return f(0);
}
int main() {
printf("%d\n", add1(33));
printf("%d\n", indirect42(add1));
printf("%d\n", indirect0(add1));
printf("%d\n", times2(33));
printf("%d\n", indirect42(times2));
printf("%d\n", indirect0(times2));
return 0;
}
Here, I call the function add1()
on my own first, then I tell two other functions to use that function for their own purpose. Then I do the same with another function.
And this works perfectly - both functions are called with 33 by me, then with 42 and with 0. And the results - 34, 43 and 1 for the first and 66, 84 and 0 for the 2nd function - match the expectations.
If we have a look at the x86 assembler output, we see
…
indirect42:
.LFB13:
.cfi_startproc
movl 4(%esp), %eax
movl $42, 4(%esp)
jmp *%eax
.cfi_endproc
The function gets the given function pointer into %eax
, then puts the 42
where it is expected and then calls %eax
. (Resp., as I activated optimization, it jumps there. The logic remains the same.)
The function doesn't know which function is to be called, but how it is to be called.
indirect0:
.LFB14:
.cfi_startproc
movl 4(%esp), %eax
movl $0, 4(%esp)
jmp *%eax
.cfi_endproc
The function does the same as the other one, but it passes 0
to whatever function it gets.
Then, as it comes to calling all this stuff, we get
movl $33, (%esp)
call add1
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
Here we have a normal function call.
movl $add1, (%esp)
call indirect42
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
Here, the address of add1
is pushed to the stack and given to indirect42
so that function can do with it as it wants.
movl $add1, (%esp)
call indirect0
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
The same with indirect0
.
(other stuff snipped as it works the same)