簡體   English   中英

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函數一樣在編譯時解析它呢? 我的問題是,如果我在編譯時知道add(x,y) ,那么我也可以在編譯時預測p_add

以下是 gcc 和 Clang 為您現在的代碼生成的內容:

main:                                   # @main
    xor     eax, eax
    ret

Godbolt 上的代碼

所以在這種情況下,我們實際上沒有早期或晚期綁定。 相反,我們根本沒有綁定到函數——您沒有使用從調用函數中獲得的結果(直接或通過指針),因此編譯器根本沒有生成任何代碼來調用函數全部。

我們可以使用此訂單上的代碼修復它:

#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:

Godbolt 上的代碼

所以,我們仍然沒有任何真正的“綁定”到函數。 讓我們讓它使用直到運行時才知道的輸入:

#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)

Godbolt 上的代碼

概括

如果在編譯時很明顯將調用哪個函數,則編譯器可能不會生成代碼來通過指針調用該函數,即使源代碼是這樣顯示的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM