Почему вы должны связать математическую библиотеку в C?

Если я включу <stdlib.h> или же <stdio.h> в программе на C мне не нужно связывать их при компиляции, но я должен ссылаться на <math.h>, с помощью -lm с помощью gcc, например:

gcc test.c -o test -lm

Что является причиной этого? Почему я должен явно связать математическую библиотеку, а не другие библиотеки?

12 ответов

Решение

Функции в stdlib.h а также stdio.h есть реализации в libc.so (или же libc.a для статической компоновки), которая по умолчанию связана с вашим исполняемым файлом (как будто -lc были указаны). GCC можно поручить избегать этой автоматической связи с -nostdlib или же -nodefaultlibs опции.

Математические функции в math.h есть реализации в libm.so (или же libm.a для статического связывания) и libm по умолчанию не связан Есть исторические причины для этого libm/libc Расколотый, ни один из них не очень убедительный.

Интересно, что C++ Runtime libstdc++ требует libm, так что если вы компилируете программу на C++ с GCC (g++), вы автоматически получите libm связаны в.

Помните, что C является старым языком, а FPU - явление относительно недавнее. Я впервые увидел C на 8-битных процессорах, где было много работы, чтобы выполнить даже 32-битную целочисленную арифметику. Многие из этих реализаций даже не имели доступной математической библиотеки с плавающей точкой!

Даже на первых 68000 машин (Mac, Atari ST, Amiga) сопроцессоры с плавающей запятой часто были дорогими дополнениями.

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

Компромиссы существовали в течение длительного времени. Иногда встречались конкурирующие математические пакеты, называемые "fastmath" или подобные. Какое лучшее решение для математики? Действительно точный, но медленный материал? Неточно, но быстро? Большие таблицы для тригонометрических функций? Лишь в тех случаях, когда сопроцессоры были гарантированно находиться в компьютере, большинство реализаций стало очевидным. Я предполагаю, что где-то прямо сейчас есть какой-то программист, работающий над встроенным чипом, пытающийся решить, стоит ли вводить математическую библиотеку для решения какой-то математической задачи.

Вот почему математика не была стандартной. Многие или, может быть, большинство программ не использовали один float. Если бы FPU всегда были рядом, а поплавки и парные удары всегда были дешевы в эксплуатации, без сомнения, это был бы "случай".

Объяснение дается здесь:

Так что, если ваша программа использует математические функции и в том числе math.h, то вам нужно явно связать математическую библиотеку, передав -lm флаг. Причина этого конкретного разделения состоит в том, что математики очень разборчивы в способе вычисления их математики, и они могут захотеть использовать свою собственную реализацию математических функций вместо стандартной реализации. Если математические функции были сосредоточены в libc.a это было бы невозможно сделать.

[Редактировать]

Я не уверен, что согласен с этим, хотя. Если у вас есть библиотека, которая обеспечивает, скажем, sqrt(), и вы передаете его перед стандартной библиотекой, линкер Unix возьмет вашу версию, верно?

Подробное обсуждение ссылок на внешние библиотеки приведено в разделе "Введение в GCC - Связь с внешними библиотеками". Если библиотека является членом стандартных библиотек (например, stdio), вам не нужно указывать компилятору (на самом деле компоновщику), чтобы связать их.

РЕДАКТИРОВАТЬ: После прочтения некоторых других ответов и комментариев, я думаю, что ссылка на libc.a и ссылка на libm, на которую она ссылается, может многое сказать о том, почему оба они разделены.

Обратите внимание, что многие функции в libm.a (математическая библиотека) определены в math.h, но отсутствуют в libc.a. Некоторые из них могут сбивать с толку, но практическое правило таково: библиотека C содержит те функции, которые должны существовать в соответствии с требованиями ANSI, поэтому вам не нужен ключ -lm, если вы используете только функции ANSI. Напротив, libm.a содержит больше функций и поддерживает дополнительные функции, такие как обратный вызов matherr и соответствие нескольким альтернативным стандартам поведения в случае ошибок FP. Смотрите раздел libm, для более подробной информации.

Как сказал ephemient, библиотека C libc по умолчанию связана, и эта библиотека содержит реализации stdlib.h, stdio.h и нескольких других стандартных заголовочных файлов. Просто добавьте к этому, в соответствии с " Введение в GCC" команда компоновщика для базовой программы "Hello World" на C выглядит следующим образом:

ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o 
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc 
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o

Обратите внимание на опцию -lc в третьей строке, которая связывает библиотеку C.

Если я ставлю stdlib.h или stdio.h, мне не нужно связывать их, но я должен связывать их при компиляции:

stdlib.h, stdio.h являются заголовочными файлами. Вы включаете их для вашего удобства. Они только прогнозируют, какие символы станут доступными, если вы перейдете по ссылке в соответствующую библиотеку. Реализации находятся в файлах библиотеки, где функции действительно живут.

В том числе math.h это только первый шаг к получению доступа ко всем математическим функциям.

Кроме того, вам не нужно ссылаться на libm если вы не используете его функции, даже если вы делаете #include <math.h> который является только информационным шагом для вас, для компилятора о символах.

stdlib.h, stdio.h обратитесь к функциям, доступным в libc, который всегда связан с тем, что пользователь не должен делать это сам.

Это ошибка. Вам не нужно явно указывать -lmбольше. Возможно, если на это пожалуется достаточное количество людей, это будет исправлено. (Я не верю в это всерьез, поскольку специалисты по сопровождению, которые поддерживают это различие, очевидно, очень упрямы, но я могу надеяться.)

Я думаю, что это произвольно. Вы должны нарисовать линию где-нибудь (какие библиотеки по умолчанию, а какие нужно указать).

Это дает вам возможность заменить его другим, имеющим те же функции, но я не думаю, что это очень распространено.

РЕДАКТИРОВАТЬ: (из моих собственных комментариев): Я думаю, что gcc делает это для обеспечения обратной совместимости с оригинальным cc. Я предполагаю, почему cc делает это из-за времени сборки - cc был написан для машин с гораздо меньшей мощностью, чем у нас сейчас. У многих программ нет математики с плавающей точкой, и они, вероятно, взяли каждую библиотеку, которая обычно не использовалась, по умолчанию. Я предполагаю, что время сборки ОС UNIX и инструменты, которые сопровождают ее, были движущей силой.

Я предполагаю, что это способ заставить приложения, которые вообще не используют его, работать немного лучше. Вот мои мысли по этому поводу.

Операционные системы x86 (и я полагаю, другие) должны хранить состояние FPU при переключении контекста. Тем не менее, большинство операционных систем пытаются сохранить / восстановить это состояние только после того, как приложение попытается использовать FPU в первый раз.

В дополнение к этому, вероятно, есть некоторый базовый код в математической библиотеке, который установит FPU в нормальное базовое состояние при загрузке библиотеки.

Так что, если вы вообще не будете ссылаться ни на какой математический код, ничего этого не произойдет, поэтому ОС вообще не нужно сохранять / восстанавливать состояние FPU, что делает переключение контекста немного более эффективным.

Просто предположение, хотя.

РЕДАКТИРОВАТЬ: в ответ на некоторые комментарии, та же самая базовая предпосылка все еще применяется к случаям не-FPU (предпосылка состоит в том, чтобы сделать приложения, которые не используют libm, работают немного лучше).

Например, если есть программный FPU, который был похож на ранние времена C. Тогда наличие раздельного libm могло бы предотвратить ненужное связывание большого количества (и медленного, если оно использовалось) кода.

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

stdio является частью стандартной библиотеки C, с которой по умолчанию будет ссылаться gcc.

Реализации математической функции находятся в отдельном файле libm, который не связан по умолчанию, поэтому вы должны указать его -lm. Кстати, между этими заголовочными файлами и библиотеками нет никакой связи.

Все библиотеки любят stdio.h и stdlib.h имеют свою реализацию в libc.so или же libc.aи по умолчанию связываются компоновщиком. Библиотеки для libc.soавтоматически связываются при компиляции и включаются в исполняемый файл.
Но math.h имеет свои реализации в libm.so или же libm.a который отделен от libc.so и он не связывается по умолчанию, и вам нужно вручную связать его при компиляции вашей программы в gcc используя -lm флаг.

Команда gnu gcc разработала его таким образом, чтобы он был отделен от других файлов заголовков, в то время как другие файлы заголовков связываются по умолчанию, а файл math.h - нет.

Здесь прочтите пункт 14.3, вы можете прочитать все, если хотите: Причина, по которой необходимо связать math.h
Посмотрите эту статью: почему мы должны связать math.h в gcc?
Взгляните на использование:использование библиотеки

Обратите внимание, что -lm не всегда нужно указывать, даже если вы используете некоторые математические функции C.

Например, следующая простая программа:

      #include <stdio.h>
#include <math.h>

int main() {

    printf("output: %f\n", sqrt(2.0));
    return 0;
}

можно скомпилировать и успешно запустить с помощью следующей команды:

      gcc test.c -o test

Протестировано на gcc 7.5.0 (на Ubuntu 16.04) и gcc 4.8.0 (на CentOS 7).

Сообщение здесь дает некоторые объяснения:

Вызываемые математические функции реализуются встроенными функциями компилятора.

Смотрите также:

Другие вопросы по тегам