C++ 早期绑定和后期绑定
C++ early binding and late binding
我了解了 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);
}
为什么int b=p_add(5,19)
不能在编译时解析?我们都知道它在编译时与add
函数相关联。那为什么我们不能像添加函数一样在编译期解析呢?我的问题是,如果我在编译时知道 add(x,y)
那么我也可以在编译时预测 p_add
。
以下是 gcc 和 Clang 为您的代码生成的内容:
main: # @main
xor eax, eax
ret
所以在这种情况下,我们实际上没有早期或晚期绑定。相反,我们根本没有绑定到函数——您没有使用调用函数(直接或通过指针)获得的结果,因此编译器根本没有生成任何代码来调用函数全部.
我们可以使用此订单上的代码修复该问题:
#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;
}
在这种情况下,编译器仍然检测到函数的结果在编译时不依赖于任何东西,因此它在编译时计算值,并将其作为常量打印出来:
mov esi, 24
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)ant:
因此,我们仍然没有任何真正的 "binding" 功能。让我们让它使用直到 运行-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;
}
此源代码生成以下目标代码:
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)
编译器仍然知道指针始终指向一个特定函数,因此即使源代码显示通过指针调用函数,但在目标代码中我们不会通过指针调用函数。 ..事实上,我们仍然根本不调用该函数。相反,函数主体的代码是内联生成的。
要通过指针进行实际的函数调用,我们可以使用一个指针来引用两个不同函数中的任何一个,直到 运行 时间才能知道使用这两个函数中的哪一个在特定情况下。例如:
#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;
}
这(终于!)使通过指针的调用实际上作为通过指针的调用发生:
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)
总结
如果在编译时很明显将调用什么函数,编译器可能不会生成通过指针调用函数的代码,即使源代码显示的是这样。
我了解了 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);
}
为什么int b=p_add(5,19)
不能在编译时解析?我们都知道它在编译时与add
函数相关联。那为什么我们不能像添加函数一样在编译期解析呢?我的问题是,如果我在编译时知道 add(x,y)
那么我也可以在编译时预测 p_add
。
以下是 gcc 和 Clang 为您的代码生成的内容:
main: # @main
xor eax, eax
ret
所以在这种情况下,我们实际上没有早期或晚期绑定。相反,我们根本没有绑定到函数——您没有使用调用函数(直接或通过指针)获得的结果,因此编译器根本没有生成任何代码来调用函数全部.
我们可以使用此订单上的代码修复该问题:
#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;
}
在这种情况下,编译器仍然检测到函数的结果在编译时不依赖于任何东西,因此它在编译时计算值,并将其作为常量打印出来:
mov esi, 24
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)ant:
因此,我们仍然没有任何真正的 "binding" 功能。让我们让它使用直到 运行-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;
}
此源代码生成以下目标代码:
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)
编译器仍然知道指针始终指向一个特定函数,因此即使源代码显示通过指针调用函数,但在目标代码中我们不会通过指针调用函数。 ..事实上,我们仍然根本不调用该函数。相反,函数主体的代码是内联生成的。
要通过指针进行实际的函数调用,我们可以使用一个指针来引用两个不同函数中的任何一个,直到 运行 时间才能知道使用这两个函数中的哪一个在特定情况下。例如:
#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;
}
这(终于!)使通过指针的调用实际上作为通过指针的调用发生:
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)
总结
如果在编译时很明显将调用什么函数,编译器可能不会生成通过指针调用函数的代码,即使源代码显示的是这样。