Função pow (math.h)

Função pow (math.h)

por Claynon Souza -
Número de respostas: 8

Quando uso a funçao pow() da bib math.h com argumentos constantes meus programas funcionam normalmente, mas quando uso variaveis eu recebo um erro de compilação:

/tmp/ccIm2kBd.o: In function `calcula_valor':
prog.ctriste.text+0x6d0): undefined reference to `pow'
prog.ctriste.text+0x84c): undefined reference to `pow'
collect2: ld returned 1 exit status

pow(2.0, 3.0); /*funciona*/

pow(a, b); /*ERRO*/

 

Quando compilo com a opção -lm meu programa compila normalmente. Quando compilo no windows também funciona normalmente.

Estou usando ubuntu 12.04 e gcc 4.6.3

Alguém sabe por que eu recebo esse erro e o que essa opção -lm está fazendo para compilar corretamente meu código?

Em resposta à Claynon Souza

Re: Função pow (math.h)

por José Coelho de Pina -

Oi Claynon,

Vou escrever um pouco, mas o melhor é ler a página

Linker

A mensagem de erro acima não foi gerada pelo compilador (no caso o gcc), mas sim pelo "linker" (no caso o ld).
O processo de compilação verifica se o seu programa está sintaticamente correto e, se for o caso gera os chamados "object files".
Esse object files não são arquivos executáveis. Eles possuem referências à funções que não estão no arquivo fonte do seu programa (como scanf, fscanf. . .).
Um outro programa, o "linker" e o responsável por criar o arquivo executável.
Para isto o linker recebe como entrada o object file (resultado da compilação do programa que você escreveu) e outros arquivos como arquivos de biblioteca.
No caso do pow o linker precisa da biblioteca libm.a.
A opção "-lm" que você coloca é para avisar o linker para procurar o códido do pow na biblioteca libm.a.
Só depois de encontrar o código do pow é que o linker gera o executável do seu programa.
Caso o linker não encontre todos os trechos de código que estão faltando no seu programa ele apresenta uma mensagem, como a que você recebeu.

collect2: ld returned 1 exit status

Voltando ao seu programa. Ele utiliza a função pow da biblioteca matemática do C, ele deve conter a linha

#include <math.h>

que possui o protótipo da função pow:

double pow(double,double);

Com isto o gcc não acusará erro/aviso sobre sintaxe "... pow não declarado ...".
(Sem esse protótipo o gcc supõe que pow é uma função que retorna um inteiro, por default (por negligência)).
Já a opção "-lm" avisa o linker para procurar códigos não definidos no arquivo de biblioteca libm.a.

Bem, estes são os meus não-sei-quantos-centavos (minha explicação meia-boca).

Em resposta à José Coelho de Pina

Re: Função pow (math.h)

por Claynon Souza -

Acho que entendi +/-

Mas ainda assim não respondeu minha dúvida.  Se eu escrevo e rodo os dois programas a seguir o primeiro funciona e o segundo não (o segundo só funciona se eu eu compilar com -lm enquanto o primeiro funciona sem o -lm) .

/* Prog 1 */

#include <stdio.h>

#include <math.h>

int main() {

printf("%f\n", pow(2.0, 3.0));

return 0;

}

/* Prog 2 */

#include <stdio.h>

#include <math.h>

int main() {

double a, b;

a = 2.0;

b = 3.0;

printf("%f\n", pow(a, b));

return 0;

}

Em resposta à Claynon Souza

Re: Função pow (math.h)

por José Coelho de Pina -
  1. na minha opinião os 2 não deveriam funcionar sem o -lm. . .
    Aparentemente o -lm é tão majado que vai "de graça" (como a bibliteca com o scanf. . .);
  2. para mim os 2 funcionam com o -lm (como deveriam!); e
  3. para mim os 2 funcionam sem o -lm (não gosto disto. . .).

Uso as mesmas versões de Ubuntu e gcc que você.

Em resposta à José Coelho de Pina

Re: Função pow (math.h)

por Claynon Souza -

Não entendo porquê eu deva usar -lm sendo que já estou falando no meu código para importar a biblioteca. Das poucas bibliotecas que eu usei (stdio.h, stdlib.h, string.h, float.h e math.h) só tive problemas com algumas poucas funções da math.h. Acho isso muito estranho. Na minha (principiante) opinião a forma que está rodando no seu computador faz todo sentido do mundo.

O linker é um programa desvinculado totalmente do compilador? Ele é parte do SO?

Em resposta à Claynon Souza

Re: Função pow (math.h)

por José Coelho de Pina -

Não entendo porquê eu deva usar -lm sendo que já estou falando no meu código para importar a biblioteca.

Você não está falando para usar a libm.a, você está falando que o protótipo da sua função pow é

double pow(double, double);

Você poderia usar, por exemplo, uma outra biblioteca qualquer que (e eu não conheço piscando) tem uma função pow com esse protótipo.

O linker é um programa desvinculado totalmente do compilador?

Sim. Escreva no seu prompt

meu_prompt> ld  

e depois escreva

meu_prompt> man ld

Veja também http://en.wikipedia.org/wiki/GNU_linker

Em resposta à Claynon Souza

Re: Função pow (math.h)

por José Coelho de Pina -

Entendi.

No meu caso ambos programas funcionaram com ou sem o "-lm" porque estou usando a opção "-02" de otimização.

Sem o "-lm", quando tiro o "-O2" o segundo programa acusa o erro:

pow2.c: (.text+0x2d): undefined reference to `pow'
collect2: ld returned 1 exit status

Já o primeiro programa compila beleza sem o "-lm" e sem o "-O2".
Isto se deve a alguma otimização no gcc.
No primeiro programa o gcc percebe facilmente que não há a necessidade de se chamar a função pow.
Ele simplesmente traduz pow(2.0,3.0) por 8.0 e segue o jogo.
Assim, não é necessário o ld utilizar a biblioteca matemática para gerar o executável.
Já no segundo programa, ele só faz a otimização com a opção "-O2", pois já não é tão evidente que pow é desnecessária.

Bem, achei divertido o "problema" e investigando um pouco encontrei a página http://stackoverflow.com/questions/8957967/linking-error-gcc-lm, que tem uma resposta que faz todo o sentido.

Em resposta à José Coelho de Pina

Re: Função pow (math.h)

por Claynon Souza -

Entendi (ou pelo menos acho que sim).

Na minha opinião o compilador deveria fazer essa linkagem pra não precisar desse tipo de coisa. Mas, como eu não sei coisa alguma de compiladores, minha opinião não é relevante.

Vou tentar usar -O2 na hora de compilar, eu sempre me esqueço.

E o que eu achei mais interessante do comentário do stackoverflow não tem muito a ver com essa discussão, foi o código em assembly.

Em resposta à Claynon Souza

Re: Função pow (math.h)

por William Gnann -

Chamar pow(1,2) faz o seu compilador resolver esse pow e usar uma constante no lugar. Logo não precisaremos do lm porque seu programa terá as instâncias de pow substituídas pela constante.

Chamar pow(a,b) faz o seu compilador não fazer essa otimização já que pow(a,b) não é constante. Logo precisaremos do -lm, pois precisaremos da função pow.

Experimente compilar seu exemplo utilizando -S (isso te dará um código em linguagem de montagem - boa sorte para entendê-lo! :D).