Mengapa Anda harus menautkan perpustakaan matematika di C?

254

Jika saya memasukkan <stdlib.h>atau <stdio.h>dalam program C saya tidak harus menautkan ini saat kompilasi tetapi saya harus menautkannya <math.h>, menggunakan -lmdengan gcc, misalnya:

gcc test.c -o test -lm

Apa alasannya? Mengapa saya harus secara eksplisit menghubungkan perpustakaan matematika tetapi tidak dengan perpustakaan lain?

Nggak
sumber

Jawaban:

249

Fungsi-fungsi di stdlib.hdan stdio.hmemiliki implementasi di libc.so(atau libc.auntuk menghubungkan statis), yang terhubung ke dieksekusi Anda secara default (seolah-olah -lcditentukan). GCC dapat diinstruksikan untuk menghindari tautan otomatis ini dengan -nostdlibatau -nodefaultlibsopsi.

Fungsi matematika di math.hmemiliki implementasi dalam libm.so(atau libm.auntuk tautan statis), dan libmtidak terhubung secara default. Ada alasan historis untuk ini libm/ libcsplit, tidak satupun dari mereka yang sangat meyakinkan.

Menariknya, runtime C ++ libstdc++memerlukan libm, jadi jika Anda mengkompilasi program C ++ dengan GCC ( g++), Anda akan secara otomatis libmterhubung.

singkat
sumber
8
Ini tidak ada hubungannya dengan Linux, karena sudah umum jauh sebelum Linux. Saya menduga itu ada hubungannya dengan mencoba meminimalkan ukuran yang dapat dieksekusi, karena ada banyak program yang tidak memerlukan fungsi matematika.
David Thornley
39
Pada sistem kuno, jika fungsi matematika terkandung dalam libc, maka kompilasi semua program akan lebih lambat, output executable akan lebih besar, dan runtime akan membutuhkan lebih banyak memori, tanpa manfaat untuk sebagian besar program yang tidak menggunakan fungsi matematika ini sama sekali. Saat ini kami memiliki dukungan yang baik untuk perpustakaan bersama, dan bahkan ketika menghubungkan secara statis, perpustakaan standar telah diatur sehingga kode yang tidak terpakai dapat dibuang, sehingga tidak ada lagi yang menjadi alasan yang baik lagi.
ephemient
38
@ephemient Bahkan di masa lalu, menautkan ke perpustakaan tidak menarik semua isi perpustakaan ke executable. Linker, meskipun merupakan teknologi yang sering diabaikan, secara historis cukup efisien.
7
@ephemient Juga, pustaka bersama telah ada lebih lama dari yang Anda kira. Mereka ditemukan pada 1950-an, bukan 1980-an.
5
Saya kira pada akhirnya apa yang kita lihat tidak lebih dari konservatisme GCC: "selalu berhasil seperti itu". Saya hanya berharap mereka menerapkan alasan yang sama pada ekstensi kompiler mereka.
77

Ingatlah bahwa C adalah bahasa lama dan bahwa FPU adalah fenomena yang relatif baru. Saya pertama kali melihat C pada prosesor 8-bit di mana itu banyak pekerjaan untuk melakukan bahkan aritmatika integer 32-bit. Banyak dari implementasi ini bahkan tidak memiliki perpustakaan matematika floating point!

Bahkan pada 68.000 mesin pertama (Mac, Atari ST, Amiga), coprocessor floating point seringkali merupakan pengaya yang mahal.

Untuk melakukan semua matematika floating point itu, Anda membutuhkan perpustakaan yang cukup besar. Dan perhitungannya akan lambat. Jadi, Anda jarang menggunakan pelampung. Anda mencoba melakukan segalanya dengan bilangan bulat atau bilangan bulat berskala. Ketika Anda harus memasukkan matematika. H, Anda mengertakkan gigi. Seringkali, Anda akan menulis perkiraan Anda sendiri dan tabel pencarian untuk menghindarinya.

Pertukaran ada untuk waktu yang lama. Terkadang ada paket matematika yang bersaing yang disebut "fastmath" atau semacamnya. Apa solusi terbaik untuk matematika? Benar-benar akurat tetapi lambat? Tidak akurat tetapi cepat? Tabel besar untuk fungsi trigonometri? Tidak sampai coprocessor dijamin berada di komputer yang implementasi paling jelas. Saya membayangkan ada beberapa programmer di luar sana saat ini, bekerja pada chip yang tertanam, mencoba memutuskan apakah akan membawa perpustakaan matematika untuk menangani beberapa masalah matematika.

Itu sebabnya matematika tidak standar . Banyak atau mungkin sebagian besar program tidak menggunakan float tunggal. Jika FPU selalu ada dan mengapung dan ganda selalu murah untuk beroperasi, tidak diragukan lagi akan ada "stdmath".

Nosredna
sumber
Heh, saya menggunakan pendekatan Pade untuk (1 + x) ^ y di Jawa, di PC desktop. Log, exp dan pow masih lambat.
quant_dev
Poin yang bagus. Dan saya telah melihat perkiraan untuk sin () di plugin audio.
Nosredna
11
Ini menjelaskan mengapa libmtidak ditautkan secara default, tetapi matematika adalah standar dari C89 dan sebelum itu, K&R secara de facto membakukannya, sehingga komentar "stdmath" Anda tidak masuk akal.
Fred Foo
@FredFoo Jenis dan antarmuka standar, tetapi bukan implementasinya. Saya pikir Nosredna mengacu pada perpustakaan matematika standar.
Tim Bird
72

Karena praktik sejarah konyol yang tak seorang pun mau memperbaikinya. Menggabungkan semua fungsi yang diperlukan oleh C dan POSIX ke dalam satu file library tidak hanya akan menghindari pertanyaan ini ditanyakan berulang-ulang, tetapi juga akan menghemat banyak waktu dan memori ketika menghubungkan dinamis, karena setiap .sofile yang ditautkan memerlukan operasi sistem file untuk mencari dan menemukannya, dan beberapa halaman untuk variabel statis, relokasi, dll.

Sebuah implementasi di mana semua fungsi dalam satu perpustakaan dan -lm, -lpthread, -lrt, dll pilihan semua ada-ops (atau link ke kosong .afile) yang sempurna POSIX conformant dan tentu lebih.

Catatan: Saya sedang berbicara tentang POSIX karena C sendiri tidak menentukan apa-apa tentang bagaimana kompiler dipanggil. Dengan demikian Anda bisa memperlakukan gcc -std=c99 -lmsebagai cara khusus implementasi yang harus dipanggil oleh kompiler untuk perilaku konforman.

R .. GitHub BERHENTI MEMBANTU ICE
sumber
9
+1 untuk menunjukkan bahwa POSIX tidak memerlukan libm, libc, dan librt yang terpisah. Sebagai contoh, pada Mac OS semuanya terletak dalam sistem lib tunggal (yang juga mencakup libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc dan librpcsvc).
F'x
3
–1 untuk berspekulasi tentang dampak pencarian perpustakaan pada kinerja tanpa mencadangkannya dengan tautan, atau angka. "Profil. Jangan berspekulasi"
F'x
12
Ini bukan spekulasi. Saya tidak memiliki makalah yang dipublikasikan, tetapi saya telah melakukan semua pengukuran sendiri dan perbedaannya sangat besar. Cukup gunakan stracedengan salah satu opsi waktu untuk melihat berapa banyak waktu startup dihabiskan untuk menghubungkan dinamis, atau membandingkan berjalan./configure pada sistem di mana semua utilitas standar terkait-statis versus satu di mana mereka terhubung-dinamis. Bahkan pengembang aplikasi desktop utama dan integrator sistem mengetahui biaya tautan dinamis; inilah mengapa hal-hal seperti prelink ada. Saya yakin Anda dapat menemukan tolok ukur di beberapa surat kabar itu.
R .. GitHub BERHENTI MEMBANTU ICE
1
Perhatikan bahwa POSIX memang perlu -lmditerima dan aplikasi yang menggunakan antarmuka matematika harus digunakan -lm, tetapi itu bisa menjadi opsi internal yang ditangani (atau bahkan diabaikan) oleh perintah kompiler, bukan file perpustakaan yang sebenarnya. Atau bisa juga berupa .afile kosong jika antarmuka berada di libc utama.
R .. GitHub BERHENTI MEMBANTU ICE
6
@ FX: Tidak tahu mengapa saya lupa menyebutkan ini sebelumnya: strace -ttakan dengan mudah menunjukkan waktu yang dihabiskan untuk menghubungkan dinamis. Itu tidak cantik. Dan di Linux, menginspeksi /proc/sys/smapsakan menunjukkan kepada Anda memori di atas perpustakaan tambahan.
R .. GitHub BERHENTI MEMBANTU ICE
33

Karena time()dan beberapa fungsi lain builtindidefinisikan di C library ( libc) itu sendiri dan GCC selalu menautkan ke libc kecuali Anda menggunakan -ffreestandingopsi kompilasi. Namun fungsi matematika hidup di libmmana tidak secara implisit dihubungkan oleh gcc.

ismail
sumber
8
Pada LLVM gcc saya tidak perlu menambahkan -lm. Kenapa ini?
bot47
26

Penjelasan diberikan di sini :

Jadi, jika program Anda menggunakan fungsi matematika dan termasuk math.h, maka Anda harus secara eksplisit menghubungkan perpustakaan matematika dengan melewati -lmbendera. Alasan pemisahan khusus ini adalah bahwa matematikawan sangat pilih-pilih tentang cara matematika mereka dihitung dan mereka mungkin ingin menggunakan implementasi mereka sendiri dari fungsi matematika bukannya implementasi standar. Jika fungsi matematika disatukan ke libc.adalamnya, itu tidak mungkin dilakukan.

[Sunting]

Tapi saya tidak yakin saya setuju dengan ini. Jika Anda memiliki perpustakaan yang menyediakan, katakan,, sqrt()dan Anda meneruskannya sebelum perpustakaan standar, penghubung Unix akan mengambil versi Anda, bukan?

Bastien Léonard
sumber
10
Saya tidak berpikir ada jaminan bahwa itu akan terjadi; Anda mungkin berakhir dengan konflik simbol sebagai gantinya. Mungkin akan tergantung pada linker dan tata letak perpustakaan. Saya masih menemukan alasan itu lemah; jika Anda membuat fungsi sqrt kustom, Anda benar-benar tidak harus memberikan nama yang sama dengan fungsi sqrt standar, bahkan jika itu melakukan hal yang sama ...
ephemient
1
Memang, membuat fungsi Anda sendiri (non-statis) bernama sqrthasil dalam program dengan perilaku yang tidak terdefinisi.
R .. GitHub BERHENTI MEMBANTU ICE
@Bastien Bagus temukan. Dan sampai pada titik Anda, apa yang Anda maksud dengan "sebelum perpustakaan standar"? Saya pikir, pustaka standar ditautkan secara default dan tidak perlu ditautkan melalui opsi baris perintah. Jadi, perpustakaan standar akan menjadi yang pertama untuk linker dan seseorang tidak dapat menempatkan implementasi mereka sendiri "sebelum perpustakaan standar".
Rocky Inde
@ RockyInde: lihat jawaban saya, saya pikir sebenarnya saya maksudkan "sebelum perpustakaan matematika standar". Tapi saya pikir ada opsi kompiler untuk tidak menautkan pustaka C standar, yang akan memungkinkan Anda untuk melewati pustaka Anda.
Bastien Léonard
@ BastienLéonard Saya menggunakan gcc versi 7.2, yang -lmsepenuhnya opsional. Ada ide
Donghua Liu
5

Ada diskusi menyeluruh tentang penautan ke perpustakaan eksternal di An Pengantar GCC - Menghubungkan dengan perpustakaan eksternal . Jika perpustakaan adalah anggota dari perpustakaan standar (seperti stdio), maka Anda tidak perlu menentukan ke kompiler (benar-benar penghubung) untuk menautkannya.

EDIT: Setelah membaca beberapa jawaban dan komentar yang lain, saya pikir referensi libc.a dan referensi libm yang terhubung ke keduanya memiliki banyak pendapat tentang mengapa keduanya terpisah.

Perhatikan bahwa banyak fungsi di 'libm.a' (perpustakaan matematika) didefinisikan dalam 'math.h' tetapi tidak ada di libc.a. Beberapa di antaranya, yang mungkin membingungkan, tetapi aturan praktisnya adalah ini - pustaka C berisi fungsi-fungsi yang harus ada dalam ANSI, sehingga Anda tidak memerlukan -lm jika Anda hanya menggunakan fungsi ANSI. Sebaliknya, `libm.a 'mengandung lebih banyak fungsi dan mendukung fungsionalitas tambahan seperti panggilan balik matherr dan kepatuhan terhadap beberapa standar perilaku alternatif jika terjadi kesalahan FP. Lihat bagian libm, untuk lebih jelasnya.

Bill the Lizard
sumber
1
Yang tidak menjawab pertanyaan mengapa Anda harus menautkan di perpustakaan pertandingan secara terpisah. Jelas Anda ingin harus menautkan pustaka OpenGL secara terpisah, tetapi perpustakaan pustaka matematika umumnya bermanfaat.
David Thornley
@ David: Benar sekali. Tidak jelas bagi saya dari pertanyaan bahwa ini adalah sedikit yang ditanyakan OP. Saya sedang mengedit jawaban saya saat Anda berkomentar.
Bill the Lizard
Saya tahu alasan saya menyusun program yang menggunakan sqrtfungsi dan berfungsi tanpa menyertakan perpustakaan melalui -lm. Terima kasih!
L_K
5

Seperti kata ephemient, libc perpustakaan C dihubungkan secara default dan perpustakaan ini berisi implementasi stdlib.h, stdio.h dan beberapa file header standar lainnya. Hanya untuk menambahkannya, menurut " An Introduction to GCC " perintah linker untuk program dasar "Hello World" di C adalah sebagai berikut:

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

Perhatikan opsi -lc di baris ketiga yang menghubungkan perpustakaan C.

ardsrk
sumber
3

Saya pikir itu agak sewenang-wenang. Anda harus menggambar garis di suatu tempat (perpustakaan mana yang default dan yang perlu ditentukan).

Ini memberi Anda kesempatan untuk menggantinya dengan yang berbeda yang memiliki fungsi yang sama, tetapi saya tidak berpikir itu sangat umum untuk melakukannya.

EDIT: (dari komentar saya sendiri): Saya pikir gcc melakukan ini untuk menjaga kompatibilitas dengan cc asli. Dugaan saya mengapa cc melakukan ini adalah karena waktu pembuatan - cc ditulis untuk mesin dengan daya yang jauh lebih sedikit daripada yang kita miliki sekarang. Banyak program tidak memiliki matematika floating-point dan mereka mungkin mengambil setiap perpustakaan yang biasanya tidak digunakan dari default. Saya menduga bahwa waktu pembuatan OS UNIX dan alat-alat yang menyertainya adalah kekuatan pendorong.

Lou Franco
sumber
Saya pikir mentalitas di balik pertanyaannya adalah bahwa isi libm sebagian besar merupakan bagian dari pustaka C standar, mengapa mereka tidak berada di libc?
Evan Teran
1
Alasan untuk gcc adalah menjaga kompatibilitas dengan cc asli di AT&T Unix. Saya menggunakan 3B2 pada tahun 1988 dan Anda harus -lm untuk mendapatkan matematika. Tampaknya benar-benar sewenang-wenang bagi saya pada saat itu. Di Visual Studio, saya tidak ingat pernah menambahkan matematika, tetapi Anda harus menambahkan pustaka c-runtime lain yang kadang-kadang tampak. Saya berasumsi bahwa vendor compiler punya alasan (build time?), Tetapi sekarang, saya yakin gcc hanya mencoba untuk kompatibel ke belakang.
Lou Franco
3

Jika saya meletakkan stdlib.h atau stdio.h, saya tidak harus menautkannya tetapi saya harus menautkannya ketika saya kompilasi:

stdlib.h, stdio.hadalah file header. Anda memasukkannya untuk kenyamanan Anda. Mereka hanya memperkirakan simbol apa yang akan tersedia jika Anda menautkan di perpustakaan yang tepat. Implementasinya ada di file library, di situlah fungsi tersebut benar-benar hidup.

Termasuk math.hhanyalah langkah pertama untuk mendapatkan akses ke semua fungsi matematika.

Juga, Anda tidak perlu menautkan libmjika Anda tidak menggunakan fungsi-fungsinya, bahkan jika Anda melakukan #include <math.h>yang hanya merupakan langkah informasi bagi Anda, untuk kompiler tentang simbol.

stdlib.h, stdio.hlihat fungsi yang tersedia di libc, yang kebetulan selalu ditautkan sehingga pengguna tidak harus melakukannya sendiri.

Adrian Panasiuk
sumber
2

stdio adalah bagian dari pustaka C standar yang, secara default, gcc akan terhubung.

Implementasi fungsi matematika berada dalam file libm terpisah yang tidak ditautkan secara default sehingga Anda harus menentukannya -lm. Omong-omong, tidak ada hubungan antara file header dan file library.


sumber
3
dia tahu itu .. dia bertanya mengapa
Evan Teran
Dia bilang kenapa. Simon menjelaskan bahwa beberapa pustaka ditautkan secara default, seperti stdio sedangkan pustaka matematika tidak ditautkan secara default sehingga harus ditentukan.
mnuzzo
5
Saya akan mengatakan bahwa sifat pertanyaannya adalah menanyakan mengapa libm tidak dihubungkan secara default (atau bahkan terpisah dari libc) karena isinya sebagian besar merupakan bagian dari pustaka standar c.
Evan Teran
2

Saya kira itu adalah cara untuk membuat aplikasi yang tidak menggunakannya sama sekali berfungsi sedikit lebih baik. Inilah pemikiran saya tentang ini.

OS x86 (dan saya bayangkan orang lain) perlu menyimpan status FPU pada sakelar konteks. Namun, sebagian besar OS hanya repot untuk menyimpan / mengembalikan keadaan ini setelah aplikasi mencoba menggunakan FPU untuk pertama kalinya.

Selain itu, mungkin ada beberapa kode dasar di perpustakaan matematika yang akan mengatur FPU ke keadaan dasar yang waras ketika perpustakaan dimuat.

Jadi, jika Anda tidak menautkan kode matematika sama sekali, semua ini tidak akan terjadi, oleh karena itu OS tidak harus menyimpan / mengembalikan keadaan FPU sama sekali, membuat konteks beralih sedikit lebih efisien.

Tapi tebak saja.

EDIT: dalam menanggapi beberapa komentar, premis dasar yang sama masih berlaku untuk kasus-kasus non-FPU (premisnya adalah membuat aplikasi yang tidak menggunakan libm berkinerja sedikit lebih baik).

Sebagai contoh, jika ada soft-FPU yang likley pada hari-hari awal C. Kemudian memiliki libm terpisah dapat mencegah banyak kode besar (dan lambat jika digunakan) dari yang tidak perlu terhubung.

Selain itu, jika hanya ada tautan statis yang tersedia, maka argumen yang sama berlaku bahwa itu akan menjaga ukuran yang dapat dieksekusi dan kompilasi kali turun.

Evan Teran
sumber
Jika Anda tidak terhubung dengan libm tetapi menyentuh FPU x87 melalui cara lain (operasi pada float, misalnya), kernel x86 perlu menyimpan status FPU. Saya tidak berpikir ini adalah tebakan yang sangat bagus ...
#
tentu saja jika Anda secara manual menggunakan FPU, kernel masih perlu menyimpan / mengembalikan kondisinya. Saya mengatakan bahwa jika Anda tidak pernah menggunakannya (termasuk tidak menggunakan libm) maka itu tidak perlu.
Evan Teran
Sungguh itu bisa sangat tergantung pada kernel. Pustaka matematika yang digunakan kernel dapat memiliki fungsi save_FPU_on_switch () yang menyalakannya, sementara yang lain hanya mendeteksi jika FPU disentuh.
Earlz
1
Jika saya ingat dengan benar, seluruh masalah lama mendahului floating point coprocessors bahkan pada mikroprosesor.
Nosredna
@earlz: pendekatan memiliki perpustakaan menyimpan permintaan matematika akan menjadi desain yang mengerikan. Bagaimana jika mereka menggunakan FPU dengan cara lain? Satu-satunya pendekatan yang waras (selain hanya selalu menabung / memulihkan) adalah mendeteksi penggunaan dan kemudian mulai menabung / memulihkan.
Evan Teran