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



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



gcc test.c -o test -lm


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

683   9  

9 ответов:

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

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

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

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

[Edit]

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

Как сказал Эфемер, библиотека 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++.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

просто догадка, хотя.

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

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

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

Comments

    Ничего не найдено.