Problema função inline

13. Re: Problema função inline

Reis
gnu_reis

(usa Slackware)

Enviado em 29/08/2008 - 11:20h

Cara, acho que sei o que aconteceu contigo, provavelmente vc utilizou o comando gcc e o correto é g++, por se tratar de um código em c++ e não se esqueça de combinar os módulos, -combine teste.cpp, ai vc irá chegar no mesmo ponto que estou.

Valeu!


  


14. Re: Problema função inline

Marcelo A. B. Slomp
mslomp

(usa Slackware)

Enviado em 29/08/2008 - 13:05h

o comando "gcc" é apenas o front-end core do gcc. ele se encarregará de definir se o código sendo compilado é c ou c++. na verdade o g++ é apenas um wrap para o gcc, sendo mandatório apenas em casos muito específicos.

outra coisa importante acerca de métodos inline:
em c++ os métodos inline são tratados como static. ou seja, o compilador irá emitir o código da função inline como uma referência fixa na seção de código (.text). isso soa meio paradoxal, mas faz sentido visto que o método pertence a uma classe independente da porção que a utiliza. para que ocorra a substituição efetiva ao longo do código, você deve utilizar o atributo always-inline no protótipo:

inline void altera(int) __attribute__((always_inline));

isso pode ser facilmente observado através do disassemble do código-objeto resultante para a função main (que teoricamente deveria possuir o código de teste::altera):
caso 1: sem atributo
# objdump -d exec.o
exec.o: file format elf32-i386

Disassembly of section .text:

00000000 <main>:
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: 55 push %ebp
b: 89 e5 mov %esp,%ebp
d: 51 push %ecx
e: 83 ec 24 sub $0x24,%esp
11: c7 44 24 04 0a 00 00 movl $0xa,0x4(%esp)
18: 00
19: 8d 45 f8 lea -0x8(%ebp),%eax
1c: 89 04 24 mov %eax,(%esp)
1f: e8 fc ff ff ff call 20 <main+0x20>
24: b8 00 00 00 00 mov $0x0,%eax
29: 83 c4 24 add $0x24,%esp
2c: 59 pop %ecx
2d: 5d pop %ebp
2e: 8d 61 fc lea -0x4(%ecx),%esp
31: c3 ret
Disassembly of section .text._ZN5teste6alteraEi:

00000000 <_ZN5teste6alteraEi>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 55 08 mov 0x8(%ebp),%edx
6: 8b 45 0c mov 0xc(%ebp),%eax
9: 89 02 mov %eax,(%edx)
b: 5d pop %ebp
c: c3 ret

note que teste::altera não está embutida em main, que faz uma chamada a teste::altera (main:1f)

caso 2: com atributo:
# objdump -d exec.o
exec.o: file format elf32-i386

Disassembly of section .text:

00000000 <main>:
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: 55 push %ebp
b: 89 e5 mov %esp,%ebp
d: 51 push %ecx
e: 83 ec 10 sub $0x10,%esp
11: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%ebp)
18: 8b 45 f8 mov -0x8(%ebp),%eax
1b: 89 45 f4 mov %eax,-0xc(%ebp)
1e: b8 00 00 00 00 mov $0x0,%eax
23: 83 c4 10 add $0x10,%esp
26: 59 pop %ecx
27: 5d pop %ebp
28: 8d 61 fc lea -0x4(%ecx),%esp
2b: c3 ret

agora o código de teste::altera está embutido em main. em main:11 percebemos claramente a atribuição do valor 10d (0xa) ao argumento x de teste::altera (-0x8(%ebp)). esse é o código efetivo para var.altera(10)

unindo tudo o que foi dito aqui e fazendo o resumo da ópera: se você possui 2 objetos: exec.o (que contém main chamando altera como inline) e teste.o (que contém o inline teste::altera), o linker unirá as seções .text de ambas, porém a substituição inline é feita antes desse estágio ainda pelo compilador, que saberá que existe teste::altera, porém o linker não a encontrará "na hora certa e no lugar certo", daí resultando em undefined reference.


15. Re: Problema função inline

Reis
gnu_reis

(usa Slackware)

Enviado em 29/08/2008 - 13:51h

Cara, muito interessante sua resposta, mas quando eu uso o gcc ele gera o mesmo erro da resposta anterior (/tmp/ccYcBxPr.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'), já com o g++ não e eu coloquei no protótipo o atributo always_inline e mesmo assim ele gerou o erro. Realmente está difícil.


16. Re: Problema função inline

Geraldo José Ferreira Chagas Júnior
gjr_rj

(usa Debian)

Enviado em 29/08/2008 - 18:33h

Pelo que mslomp está dizendo e já disse, não dá para fazer da forma que você está querendo. O que eu concordo, porém, como você disse que sem o inline a conpilação é feita sem erro, estou tentando fazer o mesmo para entender o que está acontecendo, porém, não estou conseguindo, sempre apresenta o mesmo erro.


17. Re: Problema função inline

Reis
gnu_reis

(usa Slackware)

Enviado em 29/08/2008 - 18:39h

Não sei se ajuda, mas o comando que utilizo é o seguinte: g++ exec.cpp -combine teste.cpp


18. Re: Problema função inline

Marcelo A. B. Slomp
mslomp

(usa Slackware)

Enviado em 30/08/2008 - 15:59h

a flag -combine joga todos os fontes para o compilador de uma só vez e realiza uma análise intermodular, porém não é suportada em C++, apenas para C. mesmo que fosse, não resolveria o problema, pois ainda assim o resultaria módulos-objeto diferentes, e aqui está a chave do negócio. atente para o fato de que o problema não está na compilação, e sim na linkagem. ou seja, daqui para diante o compilador não é mais o agente ativo do processo, e sim o ld. lembre-se que quando você invoca o gcc/g++, está chamando o front-end do compilador. a ele está atribuída a tarefa de invocar, genericamente falando, o compilador em si, então o assembler, e finalmente, o linker. estes dois últimos não são parte do gcc, e sim do binutils. o linker é, digamos assim, a camada mais "burra" da coisa. ele apenas unirá os módulos, não tomará decisões, como o compilador faz internamente. se a descrição de máquina e/ou do formato alvo não permite realizar determinada união, ele simplesmente "baixa a cabeça" e pára.
para controlar o ld você pode passar flags para o gcc através de -Wl,<flags_do_ld>. é um ótimo exercício, pois de fato poderá observar o comportamento do linker e ajustá-lo para que atenda sua necessidade específica. porém nesse nosso caso não haverá jeito. em C é possível, mas não em C++.
ao remover o inline tudo correrá bem justamente porque terá uma referência ordinária externa simples, enquanto que o uso de inline não produz referência, e sim o código será embutido no local que o chama.
ideal mesmo é manter tanto a declaração quanto o protótipo no header e deixar que ambos sejam incluídos em exec.cpp através do #include, o que produzirá na saída apenas um módulo-objeto.
aqui compilou sem erros nem warnings. testei usando o gcc 4.2.4, 4.3.1, 4.3.2 e no current (4.4.0), e em todos obtive sucesso dessa forma.


19. Re: Problema função inline

Reis
gnu_reis

(usa Slackware)

Enviado em 02/09/2008 - 10:25h

Cara, obrigado pelas dicas!



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts