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

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

gcc test.c -o test -lm

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

[изменить]

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

Ответ 4

Как сказано выше, библиотека C lib lib связана по умолчанию, и эта библиотека содержит реализации 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.

Ответ 5

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

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

Ответ 6

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

Операционные системы

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

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

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

Только предположение.

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

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

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