раннее и позднее связывание с ++ - PullRequest
0 голосов
/ 01 марта 2020

Я читал о раннем и позднем связывании в 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 (x, y) во время компиляции, то я могу также предсказать p_add во время компиляции.

1 Ответ

2 голосов
/ 01 марта 2020

Вот что g cc и 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

Сводка

Если во время компиляции будет ясно, какая функция будет вызываться, компилятор, вероятно, не сгенерирует код для вызова функции через указатель, даже если это что показывает исходный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...