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

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

gcc test.c -o test -lm

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

9 ответов


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

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

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


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

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

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

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

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


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

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

[Edit]

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


Как сказал эфемерный, библиотека c libc связана по умолчанию, и эта библиотека содержит реализации stdlib.ч, с 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++.


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

EDIT: после прочтения некоторых других ответов и комментариев, я думаю, что libc.ссылка и ссылка libm, которую он ссылается на оба, может многое сказать о том, почему два-отдельно.

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


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

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


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

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

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


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

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

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

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

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


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

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

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

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

просто догадка.

изменить: в ответ на некоторые комментарии та же базовая предпосылка по-прежнему применяется к случаям, не связанным с FPU (предпосылка заключается в том, что это должно было сделать приложения, которые не использовали libm лучше.)

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

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