I read about early and late binding in C++:
int add (int x, int y)
{
return x+y;
}
int main()
{
int a=add(5,6);//early binding
int (*p_add)(int,int)=add;
int b=p_add(5,19);
}
Why can't int b=p_add(5,19)
be resolved at compile time? We all know it is associated with the add
function at compile time. Then why can't we resolve it at compile time same as add function? My problem is that if i know add(x,y)
at compile time then I may predict p_add
at compile time too.
Here's what gcc and Clang produce for your code as it stands right now:
main: # @main
xor eax, eax
ret
So in this case, we don't really have either early or late binding. Rather, we have no binding to the function at all--you didn't use the result you got from calling the function (either directly or via a pointer), so the compiler simply didn't generate any code to call the function at all.
We can repair that with code on this order:
#include <iostream>
int add (int x, int y)
{
return x+y;
}
int main()
{
int a=add(5,6);//early binding
int (*p_add)(int,int)=add;
int b=p_add(5,19);
std::cout << b;
}
In this case, the compiler still detect that the result of the function doesn't depend on anything at compile time, so it computes the value at compile time, and prints it out as a constant:
mov esi, 24
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)ant:
So, we still don't have any real "binding" to the function. Let's have it use inputs it won't know until run-time:
#include <iostream>
#include <cstdlib>
int add (int x, int y)
{
return x+y;
}
int main()
{
int x1 = rand();
int x2 = rand();
int a=add(x1, x2);//early binding
int (*p_add)(int,int)=add;
int b=p_add(x1,x2);
std::cout << b;
}
This source produces the following object code:
call rand
mov ebx, eax
call rand
mov edi, OFFSET FLAT:_ZSt4cout
lea esi, [rbx+rax]
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
The compiler is still aware that the pointer consistently points to one particular function, so even though the source code shows the function being called via a pointer, in the object code we don't call the function via a pointer...and in fact, we still don't call the function at all. Instead, the code for the body of the function has been generated inline.
To get an actual function call via a pointer, we can have a pointer that refers to either of two different functions, and it won't be apparent until run-time which of the two to use in a particular case. For example:
#include <iostream>
#include <cstdlib>
int add (int x, int y)
{
return x+y;
}
int sub(int x, int y) {
return x-y;
}
int main()
{
int x1 = rand();
int x2 = rand();
int z = rand() % 2;
int (*p_add)(int,int) = z ? add : sub;
int b=p_add(x1,x2);
std::cout << b;
}
This (finally!) make the call via a pointer actually happen as a call via a pointer:
call rand
mov edx, OFFSET FLAT:sub(int, int) ; start by assuming we'll subract
mov esi, r12d
mov edi, ebp
test al, 1 ; then see if we have an odd or even number
mov eax, OFFSET FLAT:add(int, int)
cmove rax, rdx ; if necessary, point to add
call rax ; and finally call the function via the pointer
mov edi, OFFSET FLAT:_ZSt4cout
mov esi, eax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
Summary
If it's apparent at compile time what function will be called, the compiler probably won't generate code to call the function via a pointer, even if that's what the source code shows.