336 Stimmen

Warum müssen Sie die Mathematik-Bibliothek in C verknüpfen?

Wenn ich oder in einem C-Programm einfüge, muss ich diese beim Kompilieren nicht verknüpfen, aber ich muss verknüpfen, beispielsweise mit -lm mit GCC:

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?

0 Stimmen

313voto

ephemient Punkte 189038

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

Die mathematischen Funktionen in math.h haben Implementierungen in libm.so (oder libm.a für statisches Linken), und libm wird standardmäßig nicht verknüpft. Es gibt historische Gründe für diese libm/libc-Aufteilung, keine davon überzeugend.

Interessanterweise benötigt das C++-Laufzeitmodul libstdc++ libm, sodass, wenn Sie ein C++-Programm mit GCC (g++) kompilieren, automatisch libm eingebunden wird.

0 Stimmen

OK, also wird dies zu einer Designfrage der Bibliothek - warum sind die Bibliotheken auf diese Weise partitioniert?

1 Stimmen

Ich wette, um die Build-Zeit von UNIX selbst zu optimieren (und das zugehörige Toolset). Zu dieser Zeit war es wahrscheinlich das komplexeste, was in C erstellt wurde.

0 Stimmen

Irgendetwas mit FPU-Emulation zu tun? aber für Linux erfolgt die eventuelle Emulation im Kernel und nicht in der libm.. richtig?

100voto

Nosredna Punkte 78203

Denken Sie daran, dass C eine alte Sprache ist und dass FPUs ein relativ neues Phänomen sind. Ich sah C zuerst auf 8-Bit-Prozessoren, wo es viel Arbeit war, selbst eine 32-Bit-Integer-Arithmetik durchzuführen. Viele dieser Implementierungen hatten nicht einmal eine Gleitkomma-Mathematikbibliothek verfügbar!

Selbst auf den ersten 68000-Maschinen (Mac, Atari ST, Amiga) waren Gleitkomma-Coprozessoren oft teure Erweiterungen.

Um all diese Gleitkomma-Mathematik zu machen, benötigten Sie eine ziemlich umfangreiche Bibliothek. Und die Mathematik würde langsam sein. Also haben Sie Floats selten verwendet. Sie haben versucht, alles mit Ganzzahlen oder skalierten Ganzzahlen zu machen. Wenn Sie math.h einbeziehen mussten, haben Sie die Zähne zusammengebissen. Oft haben Sie Ihre eigenen Näherungen und Suchtabellen geschrieben, um sie zu vermeiden.

Es gab lange Zeit Kompromisse. Manchmal gab es konkurrierende Mathematikpakete namens "fastmath" oder ähnliches. Was ist die beste Lösung für Mathematik? Wirklich genau, aber langsam? Ungenau, aber schnell? Große Tabellen für trigonometrische Funktionen? Es war nicht, bis Coprozessoren garantiert im Computer waren, dass die meisten Implementierungen offensichtlich wurden. Ich stelle mir vor, dass es irgendwo einen Programmierer gibt, der gerade an einem eingebetteten Chip arbeitet und entscheiden muss, ob er die Mathematikbibliothek einbezieht, um ein mathematisches Problem zu lösen.

Deshalb war Mathematik nicht standardisiert. Viele oder vielleicht die meisten Programme haben nicht einen einzigen Float verwendet. Wenn FPUs immer verfügbar gewesen wären und Floats und Doubles immer preiswert zu handhaben gewesen wären, wäre es zweifellos eine "stdmath" gegeben.

1 Stimmen

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

1 Stimmen

Guter Punkt. Und ich habe Annäherungen für sin() in Audioplugins gesehen.

13 Stimmen

Das erklärt, warum libm standardmäßig nicht verknüpft ist, aber Mathematik war ab C89 Standard und davor hatte K&R es de facto standardisiert, sodass Ihr Hinweis zu "stdmath" keinen Sinn ergibt.

91voto

Aufgrund lächerlicher historischer Praktiken, die niemand bereit ist zu beheben. Die Konsolidierung aller für C und POSIX erforderlichen Funktionen in einer einzigen Bibliotheksdatei würde nicht nur verhindern, dass diese Frage immer wieder gestellt wird, sondern auch eine erhebliche Menge an Zeit und Speicherplatz bei der dynamischen Verknüpfung sparen, da für jedes .so -Dateien erfordern die Dateisystemoperationen, um sie zu suchen und zu finden, sowie einige Seiten für ihre statischen Variablen, Umplatzierungen usw.

Ein Ansatz, bei dem alle Funktionen in einer Bibliothek sind und die Optionen -lm, -lpthread, -lrt usw. alle keine Operationen sind (oder auf leere .a -Dateien verweisen), ist perfekt POSIX-konform und sicherlich bevorzugt.

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

11 Stimmen

+1 für die Feststellung, dass POSIX nicht verlangt, dass getrennte libm, libc und librt Bibliotheken existieren. Als Beispiel befindet sich auf Mac OS alles in einer einzigen libSystem (die auch libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc und librpcsvc enthält).

5 Stimmen

-1 für Spekulationen über den Einfluss der Bibliothekssuche auf die Leistung, ohne dies mit einem Link oder Zahlen zu belegen. "Profile. Nicht spekulieren"

15 Stimmen

Dies ist keine Spekulation. Ich habe keine veröffentlichten Arbeiten, aber ich habe alle Messungen selbst durchgeführt und der Unterschied ist riesig. Verwenden Sie einfach strace mit einer der Timing-Optionen, um zu beobachten, wie viel Startzeit für das dynamische Verknüpfen aufgewendet wird, oder vergleichen Sie das Ausführen von ./configure auf einem System, auf dem alle Standard-Dienstprogramme statisch verknüpft sind, mit einem, auf dem sie dynamisch verknüpft sind. Sogar Mainstream-Entwickler von Desktop-Anwendungen und Systemintegratoren sind sich der Kosten des dynamischen Verknüpfens bewusst; deshalb gibt es Dinge wie Prelink. Ich bin sicher, Sie können Benchmarks in einigen dieser Arbeiten finden.

33voto

ismail Punkte 43244

Weil time() und einige andere Funktionen in der C-Bibliothek (libc) selbst definiert sind und GCC immer auf libc verlinkt, es sei denn, Sie verwenden die -ffreestanding Kompilierungsoption. Mathematische Funktionen hingegen befinden sich in libm, das nicht implizit von gcc verlinkt wird.

9 Stimmen

Auf LLVM gcc muss ich kein -lm hinzufügen. Warum ist das so?

0 Stimmen

@bot47 Wahrscheinlich, weil LLVM seine eigene mathematische Bibliothek hat.

29voto

Bastien Léonard Punkte 57728

Eine Erklärung wird hier gegeben:

Also, wenn Ihr Programm mathematische Funktionen verwendet und math.h einbindet, müssen Sie die Mathematikbibliothek explizit verknüpfen, indem Sie das -lm Flag übergeben. Der Grund für diese spezielle Trennung ist, dass Mathematiker sehr wählerisch sind, wie ihre Mathematik berechnet wird, und sie möchten möglicherweise ihre eigene Implementierung der Mathematikfunktionen anstelle der Standardimplementierung verwenden. Wenn die mathematischen Funktionen in libc.a zusammengefasst wären, wäre das nicht möglich.

[Bearbeiten]

Ich bin mir jedoch nicht sicher, ob ich damit einverstanden bin. Wenn Sie eine Bibliothek haben, die beispielsweise sqrt() bereitstellt, und Sie sie vor der Standardbibliothek übergeben, nimmt ein Unix-Linker Ihre Version, nicht wahr?

11 Stimmen

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

2 Stimmen

Tatsächlich führt das Erstellen Ihrer eigenen Funktion (nicht statisch) mit dem Namen sqrt zu einem Programm mit undefiniertem Verhalten.

0 Stimmen

@Bastien Guter Fund. Und zu deinem Punkt, was meinst du mit "vor der Standardbibliothek"? Ich dachte, die Standardbibliothek ist standardmäßig verknüpft und muss nicht über Befehlszeilenoptionen verknüpft werden. Also wird die Standardbibliothek der erste Anlaufpunkt für den Linker sein und man kann seine eigene Implementierung nicht "vor der Standardbibliothek" platzieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X