Неопределенная ссылка со встроенной функцией c ++

У меня есть два файла cpp:

F1.cpp

using namespace std;

int i;

void Modify();

int main()
{
 i=1;
 cout << "i main 1 = " << i << endl;
 Modify();
 cout << "i main 2 = " << i << endl;

 return 0;
}

F2.cpp

using namespace std;

extern int i;

inline void Modify()
{

  i=99;

  cout << "i modify = " << i << endl;

}

Когда я запускаю исполняемый файл, я получаю эту ошибку: F1.o: In function main: F1.cpp :(. Text + 0x4a): undefined ссылка на `Modify () 'collect2: error: ld вернул 1 статус выхода < / em>

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

Пожалуйста помоги!


person CSstudZ    schedule 26.01.2020    source источник


Ответы (3)


Определение встроенной функции должно присутствовать в каждой единице компиляции, где она используется.

Из стандарта C ++ 17 (встроенный спецификатор 10.1.6)

2 Объявление функции (11.3.5, 12.2.1, 14.3) со встроенным спецификатором объявляет встроенную функцию. Встроенный спецификатор указывает реализации, что встроенная подстановка тела функции в точке вызова предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой встроенной замены в точке вызова; однако, даже если эта встроенная подстановка опущена, все равно должны соблюдаться другие правила для встроенных функций, указанные в этом разделе.

а также

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

person Vlad from Moscow    schedule 26.01.2020
comment
Не могли бы вы быть более откровенными? Я думал, что смысл встроенных функций в том, чтобы избежать вызова функции, вставив ядро ​​функции везде, где она вызывается? - person CSstudZ; 26.01.2020
comment
Или что происходит, когда он сначала вызывается, а затем вставляется код? Итак, проблема в том, что при первом вызове функции ее нельзя найти? - person CSstudZ; 26.01.2020
comment
@CSstudZ На самом деле все наоборот. Обычно функцию можно определить только в одной единице перевода (одном файле cpp). Затем компоновщик вставляет это определение везде, где это необходимо. Если вы хотите иметь определение в нескольких единицах перевода (например, определить функцию в файле заголовка), вы должны сделать это inline (и убедиться, что все единицы перевода имеют одинаковое определение) - person Yksisarvinen; 26.01.2020
comment
@CSstudZ Компилятору необходимо знать определение функции, чтобы иметь возможность решить, включать ли ее как встроенный вызов или нет. - person Vlad from Moscow; 26.01.2020
comment
Итак, как я могу поместить его определение в свой файл F1.cpp? Поместить код F2.cpp в файл заголовков и включить этот файл .h в F1.cpp? И я бы сохранил extern int i; в файле заголовков? - person CSstudZ; 26.01.2020
comment
@CSstudZ Либо поместите определение функции в заголовок и включите заголовок в каждую единицу компиляции, где функция используется, либо скопируйте и вставьте определение из F2.cpp в F1.cpp. - person Vlad from Moscow; 26.01.2020
comment
@CSstudZ Я думал, что смысл встроенных функций в том, чтобы избежать вызова функции, вставив ядро ​​функции везде, где она вызывается? - Ключевое слово inline в C ++ практически не имеет ничего общего с фактическим встраиванием функции. Компилятор будет встроен (или нет) по своему усмотрению, независимо от предшествующего значения inline. Ключевое слово действительно имеет значение только в отношении связи и ODR (правила единого определения). - person Jesper Juhl; 26.01.2020

В вашем файле F1.cpp Modify() никогда не определялся. Это также то, к чему относится возвращаемая ошибка.

person character11    schedule 26.01.2020

void Modify();

Эта строка на самом деле является объявлением функции. Однако вы не предоставили реализацию функции (т.е. определение функции). Вы определили встроенную функцию в F2.cpp, но она не видна в F1.cpp.

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

Этот раздел C ++ FAQ может показаться вам интересным:

Примечание. Обязательно помещайте определение функции (часть между {...}) в файл заголовка, если только функция не используется только в одном файле .cpp. В частности, если вы поместите определение встроенной функции в файл .cpp и вызовете ее из другого файла .cpp, вы получите от компоновщика «неразрешенную внешнюю» ошибку.

person jignatius    schedule 26.01.2020