inline function是一個keyword,提醒compiler可以將function本體直接填入呼叫該function的位置。從這邊可以看到,優點為
廢話少說,先來一段程式碼。 測試環境
#include <stdio.h>
inline void hello()
{
printf("Hello World\n");
}
int main(void)
{
hello();
return 0;
}
可以正常編譯
$ cc -g -Wall -Werror -c -o inline_test.o inline_test.c
$ cc -g -Wall -Werror -o inline_test inline_test.o
有趣的是,換成C99就會編譯錯誤,檢查symbol的確不存在。
cc -g -Wall -Werror -std=c99 -c -o inline_test.o inline_test.c
cc -g -Wall -Werror -std=c99 -o inline_test inline_test.o
inline_test.o: In function `main':
inline_test.c:10: undefined reference to `hello'
collect2: ld returned 1 exit status
make: *** [inline_test] Error 1
$ nm inline_test.o
U hello
0000000000000000 T main
從這邊可以看到C99的inline
定義是和GNU C的extern inline
相反。所以最簡單的懶人法就是在C99裡面加上extern
收工。
#include <stdio.h>
extern inline void hello()
{
printf("Hello World\n");
}
int main(void)
{
hello();
return 0;
}
不過對於組裝工而言,為何要在inline
前面加extern
或是static
實在有趣,所以多測了幾下。沒興趣的就直接看結論吧
如果我們把程式碼改成
#include <stdio.h>
extern inline void hello()
{
int i = 100;
printf("Hello World: %d\n", i);
}
inline void hello()
{
printf("Hello World 2\n");
}
int main(void)
{
hello();
return 0;
}
在GNU C下編譯執行會印Hello World 2
,使用objdump -S
反組譯可以看到
4004f4
位址4004f4
真正的程式碼是印出Hello World2
,也就是說extern inline void hello()
裡面的程式碼是寫心酸的。另外一點有趣的是C99下面把extern inline
和inline
對調會編譯失敗。
00000000004004f4 <hello>:
int i = 100;
printf("Hello World: %d\n", i);
}
inline void hello()
{
4004f4: 55 push %rbp
4004f5: 48 89 e5 mov %rsp,%rbp
printf("Hello World 2\n");
4004f8: bf 0c 06 40 00 mov $0x40060c,%edi
4004fd: e8 ee fe ff ff callq 4003f0 <puts@plt>
}
400502: 5d pop %rbp
400503: c3 retq
0000000000400504 <main>:
int main(void)
{
400504: 55 push %rbp
400505: 48 89 e5 mov %rsp,%rbp
hello();
400508: b8 00 00 00 00 mov $0x0,%eax
40050d: e8 e2 ff ff ff callq 4004f4 <hello>
return 0;
400512: b8 00 00 00 00 mov $0x0,%eax
}
extern
定義相反。inline
只是一個宣告,不會產生symbol。要使用extern
編譯器才會產生symbol。猜測可能單純inline
是在header file宣告用,而extern inline
則是在source code實作時使用。