Dlaczego musisz połączyć bibliotekę matematyczną w C?

Jeśli dołączam <stdlib.h> lub <stdio.h> do programu C, nie muszę ich łączyć podczas kompilacji, ale muszę połączyć się z <math.h>, używając -lm z gcc, na przykład:

gcc test.c -o test -lm
Jaki jest tego powód? Dlaczego muszę jawnie połączyć bibliotekę matematyczną, a nie inne biblioteki?
Author: Chris, 2009-06-23

9 answers

Funkcje w stdlib.h i stdio.h mają implementacje w libc.so (lub libc.a do łączenia statycznego), które są domyślnie połączone z plikiem wykonywalnym(tak jakby -lc zostały określone). GCC może być poinstruowany, aby uniknąć tego automatycznego połączenia za pomocą opcji -nostdlib lub -nodefaultlibs.

Funkcje matematyczne w math.h mają implementacje w libm.so (lub libm.a dla linkowania statycznego), a libm nie jest domyślnie linkowane. Istnieją ku temu historyczne powody libm/libc split, żaden z nich bardzo przekonujące.

Co ciekawe, środowisko uruchomieniowe C++ libstdc++ wymaga libm, więc jeśli skompilujesz program C++ z GCC (g++), automatycznie uzyskasz libm linked in.

 201
Author: ephemient,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-09 06:28:33

Pamiętaj, że C jest starym językiem i że FPU są stosunkowo nowym zjawiskiem. Po raz pierwszy zobaczyłem C na 8-bitowych procesorach, gdzie było dużo pracy, aby zrobić nawet 32-bitową arytmetykę całkowitą. Wiele z tych implementacji nie miało nawet dostępnej biblioteki matematycznej zmiennoprzecinkowej!

Nawet na pierwszych 68000 maszynach (Mac, Atari ST, Amiga), koprocesory zmiennoprzecinkowe były często drogimi dodatkami.

Aby zrobić całą tę matematykę zmiennoprzecinkową, potrzebowałeś całkiem sporej biblioteki. A matematyka miała być powolna. Więc rzadko używałeś pływaków. Próbowałeś zrobić wszystko z liczbami całkowitymi lub skalowanymi liczbami całkowitymi. Kiedy trzeba było włączyć matmę.H, zgrzytałeś zębami. Często piszesz własne przybliżenia i tabele wyszukiwania, aby tego uniknąć.

Kompromisy istniały przez długi czas. Czasami istniały konkurencyjne Pakiety matematyczne zwane "fastmath" lub takie. Jakie jest najlepsze rozwiązanie dla matematyki? Naprawdę dokładne, ale powolne rzeczy? Niedokładne, ale szybkie? Duże stoły do funkcji Tryg? Informatyka dopiero wtedy, gdy koprocesory były gwarantowane w komputerze, większość implementacji stała się oczywista. Wyobrażam sobie, że gdzieś tam jest jakiś programista, pracujący nad wbudowanym chipem, próbujący zdecydować, czy wprowadzić bibliotekę matematyczną, aby poradzić sobie z jakimś problemem matematycznym.

Dlatego matematyka nie byłastandard. Wiele, a może większość programów nie używało jednego float ' a. Gdyby FPU zawsze były w pobliżu i pływaki i duble zawsze były tanie w obsłudze, nie wątpię, żeby była "choroba weneryczna".

 64
Author: Nosredna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 17:47:51

Wyjaśnienie jest Podane tutaj:

Więc jeśli twój program używa funkcji matematycznych i zawiera math.h, musisz jawnie połączyć bibliotekę matematyczną, przekazując flagę -lm. Powodem tego szczególnego rozdzielenia jest to, że matematycy są bardzo wybredni w sposobie obliczania ich matematyki i mogą chcieć używać własnej implementacji funkcji matematycznych zamiast standardowej implementacji. Gdyby funkcje matematyczne były sumowane do libc.a to nie to możliwe.

[Edytuj]

Nie jestem pewien, czy się z tym Zgadzam. Jeśli masz bibliotekę, która dostarcza, powiedzmy, sqrt(), i przekazujesz ją przed biblioteką standardową, Linker uniksowy pobierze twoją wersję, prawda?
 25
Author: Bastien Léonard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 19:45:39

Jak powiedział ephemient, biblioteka C libc jest domyślnie połączona i ta biblioteka zawiera implementacje stdlib.H, stdio.h i kilka innych standardowych plików nagłówkowych. Aby dodać do tego, zgodnie z "An Introduction to GCC" Komenda linkera dla podstawowego programu "Hello World" w C jest jak poniżej:

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

Zwróć uwagę na opcję -LC w trzeciej linii łączącej bibliotekę C.

 5
Author: ardsrk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 18:13:08

Istnieje dokładna dyskusja na temat linkowania do zewnętrznych bibliotek w Wprowadzenie do GCC-linkowanie do zewnętrznych bibliotek . Jeśli Biblioteka jest członkiem bibliotek standardowych (takich jak stdio), to nie trzeba podawać kompilatorowi (tak naprawdę linkerowi), aby je połączyć.

EDIT: po przeczytaniu kilku innych odpowiedzi i komentarzy, myślę, że libc.odniesienie i odniesienie do libm, do którego się łączy, mają wiele do powiedzenia na temat tego, dlaczego oba są osobno.

Zauważ, że wiele funkcji w ' libm.a "(biblioteka matematyczna) są zdefiniowane w " math.h', ale nie są obecne w libc.a. niektóre są, co może być mylące, ale zasada jest taka--biblioteka C zawiera te funkcje, które ANSI nakazuje, aby istniały, więc nie potrzebujesz-lm, jeśli używasz tylko funkcji ANSI. Natomiast " libm.a ' zawiera więcej funkcji i obsługuje dodatkowe funkcje, takie jak wywołanie matherr i zgodność z kilkoma alternatywnymi standardy zachowania w przypadku błędów FP. Więcej szczegółów można znaleźć w sekcji libm.

 4
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 17:36:22

Stdio jest częścią standardowej biblioteki C, z którą domyślnie GCC będzie się łączyć.

Implementacje funkcji matematycznych znajdują się w oddzielnym pliku libm, który nie jest domyślnie połączony, więc musisz podać-lm. Nawiasem mówiąc, nie ma związku między tymi plikami nagłówkowymi a plikami bibliotecznymi.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 17:12:39

Myślę, że to trochę arbitralne. Musisz gdzieś narysować linię (które biblioteki są domyślne, a które muszą być określone).

Daje możliwość zastąpienia go innym, który ma te same funkcje, ale nie sądzę, aby to było powszechne.

EDIT: (z moich własnych komentarzy): myślę, że gcc robi to, aby zachować wsteczną kompatybilność z oryginalnym cc. Domyślam się, dlaczego cc to robi z powodu czasu budowy -- cc został napisany dla maszyn z znacznie mniej mocy niż mamy teraz. Wiele programów nie ma matematyki zmiennoprzecinkowej i prawdopodobnie zabrali wszystkie biblioteki, które nie były powszechnie używane z domyślnej. Zgaduję, że czas budowy systemu operacyjnego UNIX i narzędzia, które z nim współpracują, były siłą napędową.

 3
Author: Lou Franco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 17:24:41

Jeśli umieszczę stdlib.h lub stdio.h, nie muszę ich linkować, ale muszę linkować podczas kompilacji:

stdlib.h, stdio.h są plikami nagłówkowymi. Dołączasz je dla Twojej wygody. Przewidują one tylko, jakie symbole będą dostępne, jeśli połączysz się z odpowiednią biblioteką. Implementacje są w plikach biblioteki, to tam funkcje naprawdę żyją.

W Tym math.h jest tylko pierwszym krokiem do uzyskania dostępu do wszystkich funkcji matematycznych.

Również, nie musisz połączyć się z libm, Jeśli nie używasz jego funkcji, nawet jeśli robisz #include <math.h>, który jest tylko krokiem informacyjnym dla ciebie, dla kompilatora o symbolach.

stdlib.h, stdio.h zapoznaj się z funkcjami dostępnymi w libc, które tak się składa, że są zawsze połączone, aby użytkownik nie musiał tego robić sam.

 3
Author: Adrian Panasiuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 17:44:12

Chciałbym zgadnąć , że jest to sposób na to, aby aplikacje, które w ogóle z niego nie korzystają, działały nieco lepiej. Oto moje zdanie na ten temat.

Osy X86 (i domyślam się, że inne) muszą przechowywać stan FPU na przełączniku kontekstowym. Jednak większość systemów operacyjnych trudzi się tylko zapisaniem / przywróceniem tego stanu po tym, jak aplikacja spróbuje użyć FPU po raz pierwszy.

Oprócz tego, prawdopodobnie istnieje jakiś podstawowy kod w bibliotece matematycznej, który ustawi FPU na zdrowy stan bazowy, gdy Biblioteka jest załadowany.

Więc, jeśli nie połączysz żadnego kodu matematycznego, nic z tego się nie stanie, dlatego system operacyjny nie musi w ogóle zapisywać/przywracać żadnego stanu FPU, dzięki czemu przełączniki kontekstowe są nieco bardziej wydajne.

Tylko zgaduję.

EDIT: w odpowiedzi na niektóre komentarze, ta sama podstawowa przesłanka nadal odnosi się do przypadków innych niż FPU (założenie jest takie, że aplikacje, które nie korzystały z libm, działają nieco lepiej).

Na przykład, jeśli istnieje soft-FPU, który był podobny we wczesnych czasach C. Wtedy oddzielenie libm-a może zapobiec niepotrzebnemu linkowaniu dużej ilości (i powolnej, jeśli została użyta) kodu.

Ponadto, jeśli dostępne są tylko statyczne łącza, to stosuje się podobny argument, że utrzymywałoby to rozmiary wykonywalne i czasy kompilacji w dół.

 2
Author: Evan Teran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 18:07:16