Почему не видит функцию из библиотеки в Ардуино?

Создал простую библиотеку для ардуино:
Test_lib.h
#ifndef Test_lib_h
#define Test_lib_h
extern void Idle(void);
#endif


Test_lib.cpp
#include "Test_lib.h"
inline void  Idle(void){}


В проекте подключаю ее:
#include <Test_lib.h>
void setup() 
{
  Idle();
}

void loop() {}


Компилятор выдает ошибку:
undefined reference to `Idle()'
Но если в библиотеке убрать "inline" все работает. Почему так происходит и что делать? функция будет использоваться в прерывании, поэтому inline очень желателен.
  • Вопрос задан
  • 1149 просмотров
Пригласить эксперта
Ответы на вопрос 2
@Mercury13
Программист на «си с крестами» и не только
Запомни раз и навсегда! Inline не создаёт кода, создаёт факт его использования где-либо.
С одной стороны, inline-функция при каждом использовании должна быть определена. С другой, она не попадёт в объектный файл сама по себе.
Потому inline держат в хедерах (кроме хитрых случаев вроде private inline, когда синтаксически нельзя эту функцию вызвать откуда попало, а хедер лучше не засорять).

Когда доберётесь до шаблонов Си++ — они обладают теми же свойствами. Шаблон не создаёт кода, создаёт расшаблонивание. И тоже в хедерах, кроме хитрых случаев вроде private template или шаблона, у которого есть ровно N предопределённых специализаций и (N+1)-я не нужна.

А вот полная специализация шаблонной функции типа template<> (в угловых скобках пусто, не inline) создаёт и ей место в CPP.
Ответ написан
@kacejot
Ваша программа пытается искать определение для
extern void Idle(void);
в скомпилированном файле библиотеки. Поскольку функция с модификатором inline определена в исходном файле, то, при компиляции, на каждое место, где была вызвана эта функция, будет подставлено ее тело, но (!) в границах только этого объектного файла, который собирается из данного исходного файла. В самом объектном файле функции нет (она служит лишь как способ инстанцирования кода, без сдвигов по стеку вызова), поэтому мы не можем взять ее адрес, чтобы другие объектные файлы могли ее импортировать. Есть лишь инструкции процессора, которые были подставлены для каждого вызова этой функции.

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

Войдите, чтобы написать ответ

Похожие вопросы