Matematik kütüphanesini neden C'ye bağlamak zorundasınız?


254

Bir C programına dahil edersem <stdlib.h>veya <stdio.h>derlerken bunları bağlamak zorunda değilim, ancak gcc ile <math.h>kullanarak -lm, örneğin:

gcc test.c -o test -lm

Bunun nedeni nedir? Neden diğer kütüphaneleri değil, matematik kütüphanesini açık bir şekilde bağlamam gerekiyor?

Yanıtlar:


249

İşlevler stdlib.hve stdio.hde uygulamaları olan libc.so(ya da libc.astatik bağlama için) (sanki varsayılan olarak yürütülebilir içine bağlanır, -lcbelirtilmiş). GCC'ye -nostdlibveya -nodefaultlibsseçenekleriyle bu otomatik bağlantıyı önleme talimatı verilebilir .

İçindeki matematik işlevlerinde (veya statik bağlantı için) math.huygulamalar vardır ve varsayılan olarak bağlı değildir. Bunun / bölünmenin tarihsel nedenleri var , hiçbiri ikna edici değil.libm.solibm.alibmlibmlibc

İlginçtir, C ++ çalışma zamanı libstdc++gerektirir libm, bu nedenle GCC ( g++) ile bir C ++ programı derlerseniz , otomatik olarak libmbağlanırsınız.


8
Bunun Linux ile bir ilgisi yok, çünkü Linux'tan çok önce yaygındı. Matematik işlevlerine ihtiyaç duymayan birçok program olduğundan, yürütülebilir boyutu en aza indirmeye çalışmakla ilgili bir şey olduğundan şüpheleniyorum.
David Thornley

39
Eski sistemlerde, matematik işlevleri libc'de yer alsaydı, tüm programları derlemek daha yavaş olurdu, çıktı yürütülebilir dosyaları daha büyük olurdu ve çalışma zamanı, bu matematik işlevlerini hiç kullanmayan çoğu programın faydası olmadan daha fazla bellek gerektirecekti . Bu günlerde paylaşılan kütüphaneler için iyi bir desteğe sahibiz ve statik olarak bağlanırken bile standart kütüphaneler, kullanılmayan kodun atılabilmesi için ayarlandı, bu yüzden bunların hiçbiri artık iyi nedenler değil.
ephemient

38
@ephemient Eski günlerde bile bir kütüphaneye bağlanmak kütüphanenin tüm içeriğini yürütülebilir dosyaya çekmedi. Bağlayıcılar, sıklıkla göz ardı edilen bir teknoloji olmasına rağmen, tarihsel olarak oldukça etkilidir.

7
@ephemient Ayrıca, paylaşılan kütüphaneler düşündüğünüzden daha uzun süredir var. 1980'lerde değil, 1950'lerde icat edildi.

5
Günün sonunda baktığımız şeyin GCC muhafazakarlığından başka bir şey olmadığını düşünüyorum: "her zaman böyle çalıştı". Keşke derleyicilerinin uzantılarına aynı mantığı uygulamış olmalarını dilerdim.

77

C'nin eski bir dil olduğunu ve FPU'ların nispeten yeni bir fenomen olduğunu unutmayın. C'yi ilk önce 8 bit işlemcilerde gördüm, burada 32 bit tam sayı aritmetiği bile yapmanın çok işi vardı. Bu uygulamaların çoğunda kayan nokta matematik kütüphanesi bile yoktu !

İlk 68000 makinede bile (Mac, Atari ST, Amiga), kayan noktalı yardımcı işlemciler genellikle pahalı eklentilerdi.

Tüm bu kayan nokta matematiğini yapmak için oldukça büyük bir kütüphaneye ihtiyacınız vardı. Ve matematik yavaş olacaktı. Yani nadiren şamandıra kullandı. Her şeyi tamsayılarla veya ölçekli tamsayılarla yapmaya çalıştınız. Math.h eklemeniz gerektiğinde dişlerinizi gıcırdattınız. Bunu önlemek için genellikle kendi yaklaşımlarınızı ve arama tablolarınızı yazarsınız.

Ödünleşmeler uzun süredir vardı. Bazen "fastmath" ya da benzeri denilen rakip matematik paketleri vardı. Matematik için en iyi çözüm nedir? Gerçekten doğru ama yavaş şeyler? Yanlış ama hızlı mı? Trig fonksiyonları için büyük tablolar? Yardımcı işlemcilerin bilgisayarda olduğu garanti edilene kadar uygulamaların çoğu belli oldu. Şu anda bir yerlerde, bazı yerleşik bir çip üzerinde çalışan, bazı matematik problemlerini çözmek için matematik kütüphanesini getirip getirmemeye karar vermeye çalışan bir programcı olduğunu hayal ediyorum.

Bu yüzden matematik standart değildi . Çoğu veya belki de çoğu program tek bir şamandıra kullanmamıştır. FPU'lar her zaman etrafta olsaydı ve yüzer ve çiftler üzerinde çalışmak her zaman ucuz olsaydı, şüphesiz bir "stdmath" olurdu.


Heh, bir masaüstü bilgisayarda Java'da (1 + x) ^ y için Pade yaklaşımları kullanıyorum. Log, exp ve pow hala yavaş.
quant_dev

İyi bir nokta. Ve ses eklentilerinde sin () için yaklaşımlar gördüm.
Nosredna

11
Açıklıyor libmvarsayılan olarak bağlantılı değildir, ama matematik oldu standart C89 den ve bundan önce, K & R vardı fiili senin "stdmath" sözler anlam ifade etmiyor bu yüzden, bunu standardize.
Fred Foo

@FredFoo Türler ve arayüzler standartlaştırıldı, ancak uygulamalar değil. Bence Nosredna standart bir matematik kütüphanesine atıfta bulunuyor.
Tim Bird

72

Kimsenin düzeltmeye istekli olmadığı saçma tarihsel uygulama yüzünden. C ve POSIX için gereken tüm işlevlerin tek bir kütüphane dosyasında birleştirilmesi, bu sorunun tekrar tekrar sorulmasını önlemekle kalmaz, aynı zamanda dinamik bağlantı yaparken önemli miktarda zaman ve bellek tasarrufu sağlar, çünkü .sobağlı her dosya dosya sistemi işlemlerini gerektirir onu bulmak ve bulmak için ve statik değişkenleri, yer değiştirmeleri vb. için birkaç sayfa.

Tüm bu fonksiyonlar kütüphane ve vardır bir uygulama -lm, -lpthread, -lrtvb seçenekleri tüm no-op (veya boş bağlantı vardır .adosyalar) mükemmel olan POSIX uyumlu ve kesinlikle tercih.

Not: POSIX hakkında konuşuyorum çünkü C'nin kendisi derleyicinin nasıl çağrıldığı hakkında bir şey belirtmiyor. Böylece gcc -std=c99 -lm, derleyicinin uygun davranış için çağrılması gereken uygulamaya özgü bir yol olarak davranabilirsiniz.


9
POSIX'in ayrılmış libm, libc ve librt kütüphanelerinin varlığını gerektirmediğini belirtmek için +1. Örnek olarak, Mac OS'ta her şey tek bir libSystem'de bulunur (libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc ve librpcsvc'i de içerir).
F'x

3
–1 bir bağlantıyla veya numaralarla yedeklemeden performans üzerindeki kütüphane arama etkisi hakkında spekülasyon yapmak için. "Profil. Spekülasyon yapma"
F'x

12
Bu bir spekülasyon değil. Yayınlanmış makalem yok, ancak tüm ölçümleri kendim yaptım ve fark çok büyük. straceDinamik bağlantı için ne kadar başlangıç ​​zamanı harcandığını izlemek için zamanlama seçeneklerinden biriyle birlikte kullanın veya ./configuretüm standart yardımcı programların statik bağlı olduğu bir sistemle dinamik bağlı oldukları bir sistemde çalışmayı karşılaştırın . Ana masaüstü uygulama geliştiricileri ve sistem entegratörleri bile dinamik bağlantı maliyetlerinin farkındadır; bu yüzden ön bağlantı gibi şeyler var. Eminim bu makalelerin bazılarında kriterler bulabilirsiniz.
R .. GitHub DURDURMA BUZA YARDIM EDİYOR

1
POSIX o Not gelmez gerektiren -lmkabul edilmiş ve kullanmalıdır matematik arabirimlerini kullanan uygulamalar edilecek -lm, ancak bir iç seçenek derleyici komutu, gerçek bir kitaplık dosyası tarafından ele (hatta göz ardı) olabilir. Veya .aarayüzler ana libc'de ise sadece boş bir dosya olabilir.
R. .. GitHub DURDURMA BUZA YARDIMCI ÇALIŞMA

6
@FX: Neden daha önce bahsetmeyi unuttuğumu bilmiyorum: strace -ttDinamik bağlantı için harcanan zamanı kolayca gösterecek Güzel değil. Ve Linux'ta, inceleme /proc/sys/smapssize ek kitaplıkların bellek yükünü gösterecektir.
R .. GitHub BUZA YARDIMCI DURDUR

33

Çünkü time()ve diğer bazı işlevler builtinC kütüphanesinde ( libc) tanımlanır ve derleme seçeneğini kullanmadığınız sürece GCC her zaman libc'ye bağlanır . Bununla birlikte , gcc ile örtük olarak bağlantılı olmayan matematik fonksiyonları yaşar .-ffreestandinglibm


8
LLVM gcc'de -lm eklemek zorunda değilim. Bu neden?
bot47

26

Burada bir açıklama verilmiştir :

Yani programınız matematik fonksiyonlarını kullanıyorsa ve dahil ederse math.h, -lmbayrağı geçirerek matematik kütüphanesini açıkça bağlamanız gerekir . Bu ayrılmanın nedeni, matematikçilerin matematik hesaplanma şekli konusunda çok seçici olmaları ve standart uygulama yerine matematik işlevlerini kendi uygulamalarını kullanmak isteyebilmeleridir. Eğer matematik işlevleri toplanmış libc.aolsaydı bunu yapmak mümkün olmazdı.

[Düzenle]

Buna katıldığımdan emin değilim. Diyelim ki, sağlayan bir kütüphaneniz varsa sqrt()ve bunu standart kütüphaneden önce iletirseniz, bir Unix bağlayıcı sürümünüzü alacaktır, değil mi?


10
Bunun olacağına dair bir garanti olduğunu sanmıyorum; bunun yerine bir sembol çakışması ortaya çıkabilir. Muhtemelen bağlayıcıya ve kütüphane düzenine bağlı olacaktır. Hala bu sebebi zayıf buluyorum; özel bir sqrt işlevi yapıyorsanız, aynı şeyi
yapsa

1
Aslında, sqrttanımlanmış davranışları olan bir programda kendi işlevinizi (statik olmayan) adlandırılmış sonuçlara dönüştürmek.
R .. GitHub BUZA YARDIMCI DURDUR

@Bastien İyi bul. Demek istediğim, "standart kütüphaneden önce" ile ne demek istiyorsun? Standart kitaplığın varsayılan olarak bağlandığını ve komut satırı seçenekleri aracılığıyla bağlanması gerekmediğini düşündüm. Bu nedenle, standart kütüphane bağlayıcı için ilk başvurulacak ve kişi kendi uygulamalarını "standart kütüphaneden önce" yerleştiremez.
Rocky Inde

@ RockyInde: cevabıma bak, sanırım aslında “standart matematik kütüphanesinden önce” demek istedim. Ancak, standart C kitaplığını bağlamamanız için derleyici seçenekleri olduğunu düşünüyorum, bu da sizinkini geçmenize izin verecektir.
Bastien Léonard

@ BastienLéonard Ben -lmtamamen isteğe bağlı olan 7.2 sürümü gcc kullanıyorum . Herhangi bir fikir
Donghua Liu

5

GCC'ye Giriş - Harici kütüphanelerle bağlantı kurma konusunda harici kütüphanelere bağlantı hakkında kapsamlı bir tartışma var . Bir kitaplık standart kitaplıkların (stdio gibi) bir üyesiyse, bunları bağlamak için derleyiciye (gerçekten bağlayıcı) belirtmeniz gerekmez.

DÜZENLEME: Diğer cevap ve yorumlardan bazılarını okuduktan sonra, her ikisine de bağlanan libc.a başvurusu ve libm başvurusunun ikisinin neden ayrı olduğunu söyleyecek çok şeyi olduğunu düşünüyorum.

'Libm.a' (matematik kütüphanesi) içindeki fonksiyonların birçoğunun 'math.h' de tanımlandığını, ancak libc.a'da mevcut olmadığını unutmayın. Bazıları kafa karıştırıcı olabilir, ancak başparmak kuralı şudur - C kütüphanesi ANSI dikte edilmesi gereken işlevleri içerir, böylece sadece ANSI işlevlerini kullanıyorsanız -lm'ye ihtiyacınız yoktur. Aksine, `libm.a 'daha fazla işlev içerir ve matherr geri arama ve FP hataları durumunda çeşitli alternatif davranış standartlarına uyum gibi ek işlevleri destekler. Daha fazla bilgi için libm bölümüne bakın.


1
Bu, neden maç kitaplıklarına ayrı olarak bağlanmak zorunda olduğunuz sorusunu cevaplamaz. Açıkçası OpenGL kütüphanelerini ayrı ayrı bağlamak zorundasınız, ancak tartışmalı olarak matematik kütüphaneleri genellikle yararlıdır.
David Thornley

@David: Haklısın. OP'nin sorduğu biraz bu sorudan net değildi. Siz yorum yaparken cevabımı düzenliyordum.
Kertenkele Bill

Ben sqrtfonksiyonu kullanan bir program derleme nedenini biliyorum ve üzerinden kütüphane dahil olmadan çalışır -lm. Teşekkürler!
L_K

5

Geçici olarak söylendiği gibi, C kütüphanesi libc varsayılan olarak bağlanmıştır ve bu kütüphane stdlib.h, stdio.h ve diğer standart başlık dosyalarının uygulamalarını içerir. Eklemek gerekirse , " GCC'ye Giriş " e göre, temel bir "Merhaba Dünya" programının C için bağlayıcı komutu aşağıdaki gibidir:

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

C kütüphanesini bağlayan üçüncü satırdaki -lc seçeneğine dikkat edin .


3

Bence bu biraz keyfi. Bir yere bir çizgi çizmelisiniz (hangi kütüphaneler varsayılan ve hangilerinin belirtilmesi gerekir).

Size aynı işlevlere sahip farklı bir tane ile değiştirme fırsatı verir, ancak bunu yapmanın çok yaygın olduğunu düşünmüyorum.

EDIT: (kendi yorumlarımdan): Bence gcc bunu orijinal cc ile geriye dönük uyumluluğu korumak için yapıyor. CC'nin bunu neden yaptığına dair tahminim, derleme süresinden kaynaklanıyor - cc şu anda sahip olduğumuzdan çok daha az güce sahip makineler için yazılmıştır. Birçok programın kayan nokta matematiği yoktur ve muhtemelen yaygın olarak kullanılmayan her kütüphaneyi varsayılandan çıkarmıştır. UNIX işletim sisteminin inşa süresi ve onunla birlikte gelen araçların itici güç olduğunu tahmin ediyorum.


Sorunun arkasındaki zihniyet, libm içeriğinin büyük ölçüde standart C kütüphanesinin bir parçası olduğunu düşünüyorum, neden libc'de değiller?
Evan Teran

1
Gcc'nin nedeni AT&T Unix'teki orijinal cc ile uyumluluğu korumaktır. 1988 yılında 3B2 kullandım ve matematik almak için -lm zorunda kaldı. O zamanlar benim için tamamen keyfi görünüyordu. Visual Studio'da, matematik eklemek zorunda olduğumu hatırlamıyorum, ancak bazen diğer görünüşte c-çalışma zamanı kitaplıkları eklemeniz gerekiyor. Derleyici satıcılarının bir nedeni olduğunu varsayalım (derleme zamanı?), Ancak şu anda, gcc'nin geriye dönük olarak uyumlu olmaya çalıştığını iddia ediyorum.
Lou Franco

3

Eğer stdlib.h veya stdio.h koyarsam, bunları bağlamak zorunda değilim ama derlediğimde bağlantı kurmak zorundayım:

stdlib.h, stdio.hbaşlık dosyalarıdır. Size kolaylık sağlamak için bunları dahil edersiniz. Yalnızca uygun kütüphaneye bağlanırsanız hangi sembollerin kullanılabilir olacağını tahmin ederler. Uygulamalar kütüphane dosyalarında, fonksiyonların gerçekte yaşadığı yer burası.

Dahil etme math.h, tüm matematik işlevlerine erişmenin ilk adımıdır.

Ayrıca, libmişlevlerini kullanmıyorsanız #include <math.h>, derleyiciye semboller hakkında bilgi veren bir adım bile yapsanız bile bağlantı kurmanız gerekmez .

stdlib.h, kullanıcının kendisi yapmak zorunda kalmaması için her zaman bağlı olan stdio.hmevcut işlevlere bakın libc.


2

stdio, varsayılan olarak, gcc'nin bağlanacağı standart C kütüphanesinin bir parçasıdır.

Math işlevi uygulamaları, varsayılan olarak bağlı olmayan ayrı bir libm dosyasındadır, bu nedenle -lm belirtmeniz gerekir. Bu arada, bu başlık dosyaları ile kütüphane dosyaları arasında bir ilişki yoktur.


3
O that..he soruyor bilir neden
Evan Teran

Neden olduğunu söylüyor. Simon, bazı kütüphanelerin varsayılan olarak stdio gibi bağlı olduğunu açıklarken, matematik kütüphanesinin varsayılan olarak bağlantılı olmadığından belirtilmesi gerekir.
mnuzzo

5
Sorunun doğasının, içeriğinin büyük ölçüde c standart kütüphanesinin bir parçası olduğu için libm'in neden varsayılan olarak bağlanmadığını (hatta libc'den ayrı olmadığını) sorduğunu söyleyebilirim.
Evan Teran

2

Hiç kullanmayan uygulamaları biraz daha iyi performans göstermenin bir yolu olduğunu tahmin ediyorum . İşte benim bu konudaki düşüncem.

x86 İşletim sistemleri (ve başkalarının hayal ediyorum) FPU durumunu bağlam anahtarında depolaması gerekiyor. Ancak, çoğu işletim sistemi yalnızca uygulama FPU'yu ilk kez kullanmaya çalıştıktan sonra bu durumu kaydetmeye / geri yüklemeye zahmet eder.

Buna ek olarak, matematik kütüphanesinde muhtemelen FPU kütüphane yüklendiğinde aklı başında bir duruma getirecek bazı temel kodlar vardır.

Dolayısıyla, herhangi bir matematik koduna bağlanmazsanız, bunların hiçbiri gerçekleşmez, bu nedenle işletim sisteminin herhangi bir FPU durumunu kaydetmesi / geri yüklemesi gerekmez, bağlam anahtarlarını biraz daha verimli hale getirir.

Sadece bir tahmin.

EDIT: bazı yorumlara yanıt olarak, aynı temel öncül hala FPU olmayan durumlar için geçerlidir (öncül, libm'yi kullanmayan uygulamaların biraz daha iyi performans göstermesini sağlamaktı).

Örneğin, C'nin ilk günlerinde likley olan yumuşak bir FPU varsa, libm ayrı olması çok büyük (ve kullanılmışsa yavaş) kodun gereksiz yere bağlanmasını önleyebilir.

Buna ek olarak, yalnızca statik bağlantı varsa, çalıştırılabilir boyutları ve derleme sürelerini azaltacağı konusunda benzer bir argüman uygulanır.


Libm ile bağlantı oluşturmaz ancak x87 FPU'ya başka yollarla (örneğin şamandıralar üzerinde işlemler) dokunursanız, x86 çekirdeğinin FPU durumunu kaydetmesi gerekir. Bunun çok iyi bir tahmin olduğunu sanmıyorum ...
ephemient

elbette FPU'yu manuel olarak kullanırsanız, çekirdeğin hala durumunu kaydetmesi / geri yüklemesi gerekir. Ben (eğer libm kullanmamak dahil) hiç kullanmazsanız, o zaman yapmak zorunda olmayacağını söylüyordum.
Evan Teran

Gerçekten çekirdeğe çok bağlı olabilir. Çekirdeğin kullandığı matematik kütüphanesi, onu açan bir save_FPU_on_switch () işlevine sahipken, diğerleri sadece FPU'ya dokunulduğunu algılar.
Earlz

1
Doğru hatırlıyorsam, tüm sorun uzun süre mikroişlemcilerde bile kayan nokta yardımcı işlemcilerden önce gelir.
Nosredna

@earlz: matematik kütüphanesi talebini kaydetme yaklaşımı korkunç bir tasarım olurdu. FPU'yu başka yollarla kullanırlarsa ne olur? Tek aklı başında yaklaşım (her zaman kaydetme / geri yükleme dışında) kullanımı algılamak ve ardından kaydetme / geri yüklemeye başlamak olacaktır.
Evan Teran
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.