Почему -lm не требуется в некоторых случаях при компиляции и связывании кода C?

У меня есть образец файла здесь:

#include  #include  int main(){ printf("%f\n", log(10)); } 

Когда я скомпилирую его с помощью gcc sample.c -oa он работает отлично. Я могу запустить его с ./a и он 2.302585 результат 2.302585 как и ожидалось.

Тем не менее, когда мой файл выглядит так:

 #include  #include  int main(){ double a = 10; printf("%f\n", log(a)); } 

он не компилируется с помощью gcc sample.c -oa . Вместо этого я должен использовать gcc sample.c -oa -lm чтобы я мог, по-видимому, сказать ему «ссылку на математику» … Вот где я действительно не следую, почему бы мне не связать математику в первом пример? И что именно это означает даже для того, чтобы «связать математику»? Прошло некоторое время с тех пор, как я работал с компиляторами C, так что простите меня, если это плохой вопрос.

Проверьте parsingку, и вы, скорее всего, обнаружите, что компилятор полностью оптимизирует вызов log() полностью в первом случае (так что нечего связывать), но не во втором. В этом конкретном случае glibc определяет:

 # define M_LN10 2.30258509299404568402 

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

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

… Библиотека GNU C обеспечивает оптимизацию для многих часто используемых математических функций. Когда используется GNU CC и пользователь активирует оптимизатор, определяется несколько новых встроенных функций и макросов. Эти новые функции и macros имеют те же имена, что и функции библиотеки, и поэтому используются вместо последних. В случае встроенных функций компилятор решит, разумно ли их использовать, и это решение, как правило, правильно.

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

По некоторым причинам gcc оптимизирует log (const) даже с -O0. Поэтому в первом случае вызов журнала () отсутствует. Проверьте сборку, чтобы проверить:

gcc sample.c -S

clang, например, не оптимизирует его на O0. Но в O2 gcc оптимизирует вызов в обоих случаях.