_>Получается, определив inline функцию только в заголовочном файле, и не написать декларацию в .c файле — это, в принципе, не правильно?
В смысле "декларацию в .c файле"? Может определение?
В С если у функции есть объявление (declaration), то её можно вызывать. Но для сборки программы где-то должно существовать определение (definition).
Если же у функции есть inline definition (это отдельный термин), например в виде записи в .h файле: inline int foo() { return 42; }), то ничего не меняется и где-то в программе по прежнему должно существовать определение (но при этом допустимо это определение записать в короткой форме extern int foo();, если этому предшествует inline definition).
_>На с++ такое распостраняется?
Именно на inline-функции — нет. Но в C++ есть полностью аналогичные заморочки с теми же статическими членами классов.
_>Всегда думал, что любое использование inline-функции (если компилятор решил ее не встраивать) просто приводит к созданию слабых ссылок на них, из которых линкер выберет только одну.
Это один из возможных способов реализации поведения С++. Правда там всё устроено чуть сложнее, так как, например, есть ещё требование по объединению static переменных для всех мест использования функции. Так что слабые секции создаются и в случае полного встраивания, и в случае внешнего вызова, но не для кода, а для данных.