Warum müssen Sie die Mathematikbibliothek in C verknüpfen?

Lesezeit: 11 Minuten

Nopes Benutzeravatar

Wenn ich einschließe <stdlib.h> oder <stdio.h> In einem C-Programm muss ich diese beim Kompilieren nicht verknüpfen, aber ich muss verknüpfen <math.h>verwenden -lm mit gcc zum beispiel:

gcc test.c -o test -lm

Was ist der Grund dafür? Warum muss ich die Mathematikbibliothek explizit verknüpfen, aber nicht die anderen Bibliotheken?

Benutzeravatar von ephemient
vergänglich

Die Funktionen im stdlib.h und stdio.h haben Implementierungen in libc.so (oder libc.a für statisches Linken), das standardmäßig in Ihre ausführbare Datei verlinkt ist (als ob -lc angegeben wurden). GCC kann angewiesen werden, diese automatische Verknüpfung mit dem zu vermeiden -nostdlib oder -nodefaultlibs Optionen.

Die Mathematik funktioniert in math.h haben Implementierungen in libm.so (oder libm.a für statisches Linken) und libm ist standardmäßig nicht eingebunden. Dafür gibt es historische Gründe libm/libc getrennt, keiner von ihnen sehr überzeugend.

Interessanterweise die C++-Laufzeit libstdc++ erfordert libmwenn Sie also ein C++-Programm mit GCC kompilieren (g++), erhalten Sie automatisch libm eingebunden.

  • Das hat nichts mit Linux zu tun, da es lange vor Linux üblich war. Ich vermute, es hat etwas mit dem Versuch zu tun, die ausführbare Größe zu minimieren, da es viele Programme gibt, die keine mathematischen Funktionen benötigen.

    – David Thornley

    23. Juni 2009 um 17:35 Uhr

  • Wenn auf alten Systemen mathematische Funktionen in libc enthalten wären, wäre das Kompilieren aller Programme langsamer, die ausführbaren Ausgabedateien wären größer und die Laufzeit würde mehr Speicher benötigen, ohne dass dies einen Vorteil hätte die meisten Programme, die diese mathematischen Funktionen überhaupt nicht verwenden. Heutzutage haben wir eine gute Unterstützung für gemeinsam genutzte Bibliotheken, und selbst beim statischen Linken sind die Standardbibliotheken so eingerichtet, dass unbenutzter Code verworfen werden kann, also sind all dies keine guten Gründe mehr.

    – vergänglich

    23. Juni 2009 um 17:38 Uhr

  • @ephemient Selbst in den alten Tagen hat das Verlinken auf eine Bibliothek nicht den gesamten Inhalt der Bibliothek in die ausführbare Datei gezogen. Obwohl Linker eine oft ignorierte Technologie sind, waren sie in der Vergangenheit recht effizient.

    anon

    23. Juni 2009 um 17:43 Uhr

  • @ephemient Außerdem gibt es gemeinsam genutzte Bibliotheken schon länger, als Sie vielleicht denken. Sie wurden in den 1950er Jahren erfunden, nicht in den 1980er Jahren.

    anon

    23. Juni 2009 um 17:46 Uhr

  • Ich nehme an, am Ende des Tages sehen wir nichts anderes als den GCC-Konservatismus: “So hat es immer funktioniert”. Ich wünschte nur, sie würden die gleiche Argumentation auf ihre Compiler-Erweiterungen anwenden.

    anon

    23. Juni 2009 um 17:59 Uhr

Nosrednas Benutzeravatar
Nosredna

Denken Sie daran, dass C eine alte Sprache ist und dass FPUs ein relativ neues Phänomen sind. Ich habe C zum ersten Mal auf 8-Bit-Prozessoren gesehen, wo es eine Menge Arbeit war, selbst 32-Bit-Integer-Arithmetik zu machen. Viele dieser Implementierungen nicht einmal haben eine Fließkomma-Mathematikbibliothek verfügbar!

Selbst auf den ersten 68000-Rechnern (Mac, Atari ST, Amiga) waren Gleitkomma-Coprozessoren oft teure Add-Ons.

Um all diese Gleitkommaberechnungen durchzuführen, brauchten Sie eine ziemlich umfangreiche Bibliothek. Und die Mathematik würde langsam sein. Sie haben also selten Schwimmer verwendet. Sie haben versucht, alles mit Ganzzahlen oder skalierten Ganzzahlen zu machen. Als Sie math.h einbeziehen mussten, haben Sie die Zähne zusammengebissen. Oft würden Sie Ihre eigenen Annäherungen und Nachschlagetabellen schreiben, um dies zu vermeiden.

Kompromisse gab es lange Zeit. Manchmal gab es konkurrierende Mathematikpakete namens “fastmath” oder so. Was ist die beste Lösung für Mathematik? Wirklich genaues, aber langsames Zeug? Ungenau aber schnell? Große Tabellen für trigonometrische Funktionen? Erst als Koprozessoren garantiert im Computer vorhanden waren, wurden die meisten Implementierungen offensichtlich. Ich stelle mir vor, dass gerade irgendwo da draußen ein Programmierer arbeitet, der an einem eingebetteten Chip arbeitet und versucht zu entscheiden, ob er die mathematische Bibliothek einbeziehen soll, um ein mathematisches Problem zu lösen.

Deshalb war Mathe nicht Standard. Viele oder vielleicht die meisten Programme verwendeten keinen einzigen Float. Wenn es schon immer FPUs gegeben hätte und Schwimmer und Doubles immer billig zu betreiben wären, hätte es zweifellos ein “stdmath” gegeben.

  • Heh, ich verwende Pade-Approximationen für (1 + x) ^ y in Java auf einem Desktop-PC. Log, Exp und Pow sind immer noch langsam.

    – quant_dev

    24. Juni 2009 um 6:23 Uhr

  • Guter Punkt. Und ich habe Annäherungen für sin() in Audio-Plugins gesehen.

    – Nosredna

    24. Juni 2009 um 16:03 Uhr

  • Dies erklärt warum libm ist nicht standardmäßig verlinkt, aber Mathe war es Standard von C89 und davor hatte K&R de facto standardisiert, sodass Ihre “stdmath” -Bemerkung keinen Sinn ergibt.

    – Fred Foo

    14. November 2011 um 9:36 Uhr

  • @FredFoo Die Typen und Schnittstellen wurden standardisiert, aber nicht die Implementierungen. Ich denke, Nosredna bezieht sich auf eine Standard-Mathematikbibliothek.

    – Tim Vogel

    22. Januar 2020 um 18:57 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Wegen lächerlicher historischer Praxis, die niemand zu korrigieren bereit ist. Das Konsolidieren aller von C und POSIX benötigten Funktionen in einer einzigen Bibliotheksdatei würde nicht nur vermeiden, dass diese Frage immer wieder gestellt wird, sondern würde auch viel Zeit und Speicherplatz beim dynamischen Linken sparen, da jede .so Die verknüpfte Datei erfordert die Dateisystemoperationen, um sie zu lokalisieren und zu finden, und einige Seiten für ihre statischen Variablen, Verschiebungen usw.

Eine Implementierung, bei der sich alle Funktionen in einer Bibliothek befinden und die -lm, -lpthread, -lrtetc. Optionen sind alle no-ops (oder Link to empty .a Dateien) ist perfekt POSIX-konform und sicherlich vorzuziehen.

Hinweis: Ich spreche von POSIX, weil C selbst nichts darüber angibt, wie der Compiler aufgerufen wird. So können Sie einfach behandeln gcc -std=c99 -lm als implementierungsspezifische Art und Weise, wie der Compiler für konformes Verhalten aufgerufen werden muss.

  • +1 für den Hinweis, dass POSIX nicht erfordert, dass getrennte libm-, libc- und librt-Bibliotheken existieren. Beispielsweise befindet sich unter Mac OS alles in einem einzigen libSystem (das auch libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc und librpcsvc umfasst).

    – F’x

    5. Januar 2011 um 20:38 Uhr

  • –1 für Spekulationen über die Auswirkungen der Bibliothekssuche auf die Leistung, ohne dies mit einem Link oder Zahlen zu untermauern. “Profil. Nicht spekulieren”

    – F’x

    5. Januar 2011 um 20:39 Uhr

  • Das ist keine Spekulation. Ich habe keine veröffentlichten Arbeiten, aber ich habe alle Messungen selbst durchgeführt und der Unterschied ist riesig. Benutz einfach strace mit einer der Timing-Optionen, um zu sehen, wie viel Startzeit für die dynamische Verknüpfung aufgewendet wird, oder um die Ausführung zu vergleichen ./configure auf einem System, auf dem alle Standard-Dienstprogramme statisch verknüpft sind, im Gegensatz zu einem System, auf dem sie dynamisch verknüpft sind. Selbst Mainstream-Desktop-App-Entwickler und Systemintegratoren sind sich der Kosten dynamischer Verknüpfungen bewusst; Aus diesem Grund gibt es Dinge wie Prelink. Ich bin sicher, dass Sie Benchmarks in einigen dieser Papiere finden können.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    5. Januar 2011 um 21:59 Uhr

  • @FX: Weiß nicht, warum ich vergessen habe, das vorher zu erwähnen: strace -tt zeigt Ihnen ganz einfach die Zeit, die Sie für die dynamische Verknüpfung aufgewendet haben. Es ist nicht schön. Und unter Linux inspizieren /proc/sys/smaps zeigt Ihnen den Speicheraufwand zusätzlicher Bibliotheken.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    2. April 2011 um 19:24 Uhr

  • @TimBird: Ein Großteil dieser Antwort scheint fälschlicherweise vorauszusetzen, dass das Verknüpfen einer Bibliothek alles daraus gezogen hat und nicht nur die Funktionen (mit der Granularität der Übersetzungseinheit, aber historisch wurden sie ordnungsgemäß in einzelne Funktionen aufgeteilt), die Sie verwenden.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    22. Januar 2020 um 22:13 Uhr


Da time() und einige andere Funktionen sind builtin in der C-Bibliothek definiert (libc) selbst und GCC stets Links zu libc wenn nicht Sie verwenden die -ffreestanding Kompilierungsoption. Allerdings leben mathematische Funktionen darin libm die nicht implizit von gcc gelinkt wird.

Eine Erklärung wird gegeben hier:

Wenn Ihr Programm also mathematische Funktionen verwendet und einschließt math.hdann müssen Sie die mathematische Bibliothek explizit verknüpfen, indem Sie die übergeben -lm Flagge. Der Grund für diese besondere Trennung ist, dass Mathematiker sehr wählerisch sind, was die Art und Weise angeht, wie ihre Mathematik berechnet wird, und sie möglicherweise ihre eigene Implementierung der mathematischen Funktionen anstelle der Standardimplementierung verwenden möchten. Wenn die mathematischen Funktionen in einen Topf geworfen würden libc.a das wäre nicht möglich.

[Edit]

Ich bin mir aber nicht sicher, ob ich damit einverstanden bin. Wenn Sie eine Bibliothek haben, die z. sqrt()und Sie übergeben es vor der Standardbibliothek, wird ein Unix-Linker Ihre Version übernehmen, richtig?

  • Ich glaube nicht, dass es eine Garantie dafür gibt; Sie könnten stattdessen mit einem Symbolkonflikt enden. Es würde wahrscheinlich vom Linker und dem Layout der Bibliothek abhängen. Ich finde diesen Grund immer noch schwach; Wenn Sie eine benutzerdefinierte sqrt-Funktion erstellen, sollten Sie ihr wirklich nicht denselben Namen wie der Standard-sqrt-Funktion geben, auch wenn sie dasselbe tut …

    – vergänglich

    23. Juni 2009 um 20:45 Uhr

  • In der Tat, indem Sie Ihre eigene Funktion (nicht statisch) benennen sqrt führt zu einem Programm mit undefiniertem Verhalten.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    1. August 2010 um 20:07 Uhr

  • @Bastien Guter Fund. Und um zu Ihrem Punkt zu kommen, was meinen Sie mit “vor der Standardbibliothek”? Ich dachte, die Standardbibliothek ist standardmäßig eingebunden und muss nicht über Befehlszeilenoptionen eingebunden werden. Die Standardbibliothek wird also die erste Anlaufstelle für den Linker sein, und man kann seine eigene Implementierung nicht “vor der Standardbibliothek” platzieren.

    – Rocky Inde

    5. März 2015 um 9:17 Uhr


  • @RockyInde: Schau dir meine Antwort an, ich glaube, ich meinte eigentlich „vor der Standard-Mathematikbibliothek“. Aber ich denke, es gibt Compiler-Optionen, um die Standard-C-Bibliothek nicht zu verknüpfen, was es Ihnen ermöglichen würde, Ihre zu übergeben.

    – Bastien Léonard

    5. März 2015 um 10:51 Uhr

  • @BastienLéonard Ich verwende gcc der Version 7.2, die die -lm ist völlig optional. Irgendwelche Ideen

    – Donghua Liu

    22. Juni 2018 um 1:30 Uhr

Es gibt eine ausführliche Diskussion über die Verknüpfung mit externen Bibliotheken in Eine Einführung in GCC – Verknüpfung mit externen Bibliotheken. Wenn eine Bibliothek ein Mitglied der Standardbibliotheken ist (wie stdio), müssen Sie den Compiler (eigentlich den Linker) nicht angeben, um sie zu verknüpfen.

EDIT: Nachdem ich einige der anderen Antworten und Kommentare gelesen habe, denke ich das libc.a-Referenz und die libm-Referenz, die auf beide verweist, haben viel darüber zu sagen, warum die beiden getrennt sind.

Beachten Sie, dass viele der Funktionen in ‘libm.a’ (der mathematischen Bibliothek) in ‘math.h’ definiert sind, aber nicht in libc.a vorhanden sind. Einige sind es, was verwirrend sein kann, aber die Faustregel lautet: Die C-Bibliothek enthält die Funktionen, die nach ANSI-Vorgaben vorhanden sein müssen, sodass Sie das -lm nicht benötigen, wenn Sie nur ANSI-Funktionen verwenden. Im Gegensatz dazu enthält `libm.a’ mehr Funktionen und unterstützt zusätzliche Funktionalitäten wie den matherr-Rückruf und die Einhaltung mehrerer alternativer Verhaltensstandards im Falle von FP-Fehlern. Siehe Abschnitt libm für weitere Details.

  • Ich glaube nicht, dass es eine Garantie dafür gibt; Sie könnten stattdessen mit einem Symbolkonflikt enden. Es würde wahrscheinlich vom Linker und dem Layout der Bibliothek abhängen. Ich finde diesen Grund immer noch schwach; Wenn Sie eine benutzerdefinierte sqrt-Funktion erstellen, sollten Sie ihr wirklich nicht denselben Namen wie der Standard-sqrt-Funktion geben, auch wenn sie dasselbe tut …

    – vergänglich

    23. Juni 2009 um 20:45 Uhr

  • In der Tat, indem Sie Ihre eigene Funktion (nicht statisch) benennen sqrt führt zu einem Programm mit undefiniertem Verhalten.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    1. August 2010 um 20:07 Uhr

  • @Bastien Guter Fund. Und um zu Ihrem Punkt zu kommen, was meinen Sie mit “vor der Standardbibliothek”? Ich dachte, die Standardbibliothek ist standardmäßig eingebunden und muss nicht über Befehlszeilenoptionen eingebunden werden. Die Standardbibliothek wird also die erste Anlaufstelle für den Linker sein, und man kann seine eigene Implementierung nicht “vor der Standardbibliothek” platzieren.

    – Rocky Inde

    5. März 2015 um 9:17 Uhr


  • @RockyInde: Schau dir meine Antwort an, ich glaube, ich meinte eigentlich „vor der Standard-Mathematikbibliothek“. Aber ich denke, es gibt Compiler-Optionen, um die Standard-C-Bibliothek nicht zu verknüpfen, was es Ihnen ermöglichen würde, Ihre zu übergeben.

    – Bastien Léonard

    5. März 2015 um 10:51 Uhr

  • @BastienLéonard Ich verwende gcc der Version 7.2, die die -lm ist völlig optional. Irgendwelche Ideen

    – Donghua Liu

    22. Juni 2018 um 1:30 Uhr

Benutzeravatar von ardsrk
ardsrk

Wie ephemient sagte, ist die C-Bibliothek libc standardmäßig gelinkt und diese Bibliothek enthält die Implementierungen von stdlib.h, stdio.h und mehreren anderen Standard-Header-Dateien. Nur um es hinzuzufügen, laut “Eine Einführung in GCC” Der Linker-Befehl für ein einfaches “Hello World”-Programm in C lautet wie folgt:

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

Beachten Sie die Option -lc in der dritten Zeile, die die C-Bibliothek verknüpft.

1427070cookie-checkWarum müssen Sie die Mathematikbibliothek in C verknüpfen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy