Почему так происходит?
Потому что стандарт С11 (9899:201x 6.7.4:7, черновик доступен
тут) говорит следующее про спецификатор inline:
Any function with internal linkage can be an inline function. For a function
with external linkage, the following restrictions apply: If a function is declared
with an inline function specifier, then it shall also be defined in the same translation
unit. If all of the file scope declarations for a function in a translation unit include
the inline function specifier without extern, then the definition in that translation
unit is an inline definition. An inline definition does not provide an external
definition for the function, and does not forbid an external definition in another
translation unit. An inline definition provides an alternative to an external
definition, which a translator may use to implement any call to the function
in the same translation unit. It is unspecified whether a call to the function uses
the inline definition or the external definition.
Самое главное тут -- в середине: инлайн-реализация не предоставляет и не запрещает реализацию со внешней линковкой, и в последнем предложении: транслятор волен сам выбирать, какую реализацию функции использовать -- инлайновую или со внешней линковкой.
Поскольку ты написал так:
inline void some_inline_func(uint32_t num)
{
. . .
}
ты тем самым реализовал инлайн-версию этой функции, но не реализовал версию со внешней линковкой. А транслятор выбрал (вернее ты ему подсказал выбрать, опцией -O0) использовать реализацию функции со внешней линковкой, поэтому ты получил ошибку от линковщика.
Вариантов решения этой проблемы примерно 3:
- определить функцию следующим образом:
extern inline void some_inline_func(uint32_t num)
{
. . .
}
Такая функция будет доступна из других единиц трансляции.
- либо определить функцию следующим образом:
static inline void some_inline_func(uint32_t num)
{
. . .
}
Такая функция будет доступна только для данной единицы трансляции.
- оставить в этом исходнике всё как есть, а в каком-нибудь другом определить следующую функцию:
void some_inline_func(uint32_t num)
{
. . .
}
Это самый дурацкий вариант, поскольку эти две реализации могут не совпадать и в зависимости от выбора транслятора ты можешь получить разное поведение.