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.