As funções stdlib.h
e stdio.h
têm implementações em libc.so
(ou libc.a
para vinculação estática), que são vinculadas ao seu executável por padrão (como se -lc
fossem especificadas). O GCC pode ser instruído a evitar esse link automático com as opções -nostdlib
ou -nodefaultlibs
.
As funções matemáticas em math.h
têm implementações em libm.so
(ou libm.a
para vinculação estática) e libm
não são vinculadas por padrão. Há razões históricas para este libm
/ libc
divisão, nenhuma delas muito convincente.
Curiosamente, o tempo de execução C ++ libstdc++
exige libm
, portanto, se você compilar um programa C ++ com GCC ( g++
), será automaticamente libm
vinculado.
Lembre-se de que C é uma linguagem antiga e que FPUs são um fenômeno relativamente recente. Vi C pela primeira vez em processadores de 8 bits, onde era muito trabalhoso fazer aritmética de números inteiros de 32 bits. Muitas dessas implementações nem sequer tinham uma biblioteca de matemática de ponto flutuante disponível!
Mesmo nas primeiras 68000 máquinas (Mac, Atari ST, Amiga), os coprocessadores de ponto flutuante eram frequentemente complementos caros.
Para fazer toda essa matemática de ponto flutuante, você precisava de uma biblioteca bastante considerável. E a matemática seria lenta. Então você raramente usava carros alegóricos. Você tentou fazer tudo com números inteiros ou inteiros em escala. Quando você tinha que incluir math.h, rangia os dentes. Geralmente, você escreve suas próprias aproximações e tabelas de pesquisa para evitá-lo.
As trocas existiram por um longo tempo. Às vezes, havia pacotes matemáticos concorrentes chamados "fastmath" ou algo assim. Qual é a melhor solução para matemática? Coisas realmente precisas, mas lentas? Impreciso, mas rápido? Tabelas grandes para funções trigonométricas? Não foi até que os coprocessadores estivessem no computador que a maioria das implementações se tornou óbvia. Eu imagino que há algum programador por aí em algum lugar agora, trabalhando em um chip incorporado, tentando decidir se deve trazer a biblioteca de matemática para lidar com algum problema de matemática.
É por isso que a matemática não era padrão . Muitos ou talvez a maioria dos programas não usasse um único flutuador. Se as FPUs sempre existissem e os carros alegóricos e duplos sempre fossem baratos para operar, sem dúvida haveria um "padrão".
fonte
libm
não está vinculado por padrão, mas a matemática era padrão no C89 e, antes disso, a K&R havia de fato o padronizado, de modo que sua observação "stdmath" não faz sentido.Por causa da prática histórica ridícula que ninguém está disposto a consertar. A consolidação de todas as funções exigidas por C e POSIX em um único arquivo de biblioteca não apenas evitaria que essa pergunta fosse feita repetidamente, mas também economizaria uma quantidade significativa de tempo e memória ao vincular dinamicamente, pois cada
.so
arquivo vinculado requer as operações do sistema de arquivos para localizá-lo e localizá-lo, e algumas páginas para suas variáveis estáticas, realocações etc.Uma implementação em que todas as funções estão em uma biblioteca e o
-lm
,-lpthread
,-lrt
, etc. opções são todos os não-ops (ou link para vazios.a
arquivos) está perfeitamente conformant POSIX e certamente preferível.Nota: Estou falando do POSIX porque o próprio C não especifica nada sobre como o compilador é chamado. Portanto, você pode apenas tratar
gcc -std=c99 -lm
como a maneira específica de implementação em que o compilador deve ser chamado para um comportamento compatível.fonte
strace
com uma das opções de tempo para observar quanto tempo de inicialização é gasto na vinculação dinâmica ou comparar a execução./configure
em um sistema em que todos os utilitários padrão estão vinculados à estática versus um em que eles estão vinculados à dinâmica. Até os principais desenvolvedores de aplicativos de desktop e integradores de sistemas estão cientes dos custos da vinculação dinâmica; é por isso que existem coisas como pré-ligação. Tenho certeza de que você pode encontrar referências em alguns desses documentos.-lm
para ser aceito e aplicações que usam as interfaces de matemática deve usar-lm
, mas pode ser uma opção interna tratada (ou mesmo ignorado) pelo comando do compilador, e não um arquivo de biblioteca real. Ou pode ser apenas um.a
arquivo vazio se as interfaces estiverem na libc principal.strace -tt
mostrará facilmente o tempo gasto na vinculação dinâmica. Não é bonito. E no Linux, a inspeção/proc/sys/smaps
mostrará a sobrecarga de memória de bibliotecas adicionais.Porque
time()
e algumas outras funções sãobuiltin
definidas na própria biblioteca C (libc
) e o GCC sempre se vincula à libc, a menos que você use a-ffreestanding
opção de compilação. No entanto, existem funções matemáticas naslibm
quais não está implicitamente vinculado pelo gcc.fonte
Uma explicação é dada aqui :
[Editar]
Não tenho certeza se concordo com isso, no entanto. Se você tem uma biblioteca que fornece, digamos,
sqrt()
e a passa antes da biblioteca padrão, um vinculador Unix aceita sua versão, certo?fonte
sqrt
resulta em um programa com comportamento indefinido.-lm
é totalmente opcional. Alguma idéiaHá uma discussão aprofundada sobre como vincular a bibliotecas externas em Uma introdução ao GCC - Vinculando a bibliotecas externas . Se uma biblioteca é membro das bibliotecas padrão (como stdio), não é necessário especificar ao compilador (realmente o vinculador) para vinculá-las.
EDIT: Depois de ler algumas das outras respostas e comentários, acho que a referência libc.a e a referência libm que ele vincula a ambos têm muito a dizer sobre por que os dois são separados.
fonte
sqrt
função e funciona sem incluir a biblioteca via-lm
. Obrigado!Como disse o ephemiente, a biblioteca C libc está vinculada por padrão e esta biblioteca contém as implementações de stdlib.h, stdio.h e vários outros arquivos de cabeçalho padrão. Apenas para acrescentar, de acordo com " An Introduction to GCC ", o comando linker para um programa básico "Hello World" em C é o seguinte:
Observe a opção -lc na terceira linha que vincula a biblioteca C.
fonte
Eu acho que é meio arbitrário. Você precisa desenhar uma linha em algum lugar (quais bibliotecas são padrão e quais precisam ser especificadas).
Dá a você a oportunidade de substituí-lo por um diferente, com as mesmas funções, mas não acho muito comum fazê-lo.
EDIT: (dos meus próprios comentários): Eu acho que o gcc faz isso para manter a compatibilidade com o cc original. Meu palpite sobre por que o cc faz isso é por causa do tempo de construção - o cc foi escrito para máquinas com muito menos energia do que temos agora. Muitos programas não possuem matemática de ponto flutuante e provavelmente usaram todas as bibliotecas que não eram comumente usadas fora do padrão. Suponho que o tempo de construção do SO UNIX e as ferramentas que o acompanham foram a força motriz.
fonte
stdlib.h
,stdio.h
são os arquivos de cabeçalho. Você os inclui para sua conveniência. Eles apenas prevêem quais símbolos ficarão disponíveis se você vincular na biblioteca adequada. As implementações estão nos arquivos da biblioteca, é aí que as funções realmente vivem.A inclusão
math.h
é apenas o primeiro passo para obter acesso a todas as funções matemáticas.Além disso, você não precisa se vincular
libm
se não usar suas funções, mesmo que faça uma#include <math.h>
etapa apenas informativa para o compilador sobre os símbolos.stdlib.h
,stdio.h
consulte as funções disponíveis emlibc
, que sempre estão vinculadas para que o usuário não precise fazer isso sozinho.fonte
O stdio faz parte da biblioteca C padrão com a qual, por padrão, o gcc se vincula.
As implementações da função matemática estão em um arquivo libm separado que não está vinculado por padrão, portanto, você deve especificá-lo -lm. A propósito, não há relação entre esses arquivos de cabeçalho e os arquivos de biblioteca.
fonte
Eu acho que é uma maneira de fazer com que aplicativos que não o utilizam tenham um desempenho um pouco melhor. Aqui está o meu pensamento sobre isso.
Os sistemas operacionais x86 (e imagino que outros) precisam armazenar o estado da FPU na alternância de contexto. No entanto, a maioria dos sistemas operacionais apenas se preocupa em salvar / restaurar esse estado após o aplicativo tentar usar o FPU pela primeira vez.
Além disso, provavelmente há algum código básico na biblioteca matemática que definirá a FPU para um estado de base saudável quando a biblioteca for carregada.
Portanto, se você não vincular nenhum código matemático, nada disso acontecerá; portanto, o sistema operacional não precisará salvar / restaurar nenhum estado da FPU, tornando as alternâncias de contexto um pouco mais eficientes.
Apenas um palpite.
EDIT: em resposta a alguns dos comentários, a mesma premissa básica ainda se aplica a casos que não são da FPU (a premissa é que era para fazer aplicativos que não usassem libm ter um desempenho um pouco melhor).
Por exemplo, se houver uma FPU flexível que era provável nos primeiros dias de C. A separação da libm poderia impedir que muitos códigos grandes (e lentos, se usados) fossem desnecessariamente vinculados.
Além disso, se houver apenas vinculação estática disponível, um argumento semelhante se aplica para manter os tamanhos dos executáveis e diminuir o tempo de compilação.
fonte