inline
提供: C言語入門
スポンサーリンク
inline(インライン関数指示子) とは、高速化のために「関数」を明示的に「インライン展開」させるための「指示」を与えるものです。
読み方
- inline
- いんらいん
- インライン関数指示子
- いんらいん かんすう しじし
概要
「インライン展開」するメリットは、「高速化」です。「関数呼び出しのオーバーヘッド」をなくすことができます。 従来は、マクロで実装し、マクロが展開されることによって、高速化するという手法もありましたが、「マクロによる黒魔術」は、プログラマが予想しなかったコードを生み出し、「結果が異なる」現象を引き起こしやすい面があります。
Cコンパイラの「最適化レベル」を上げないと、「インライン展開」が実施されない可能性があります。 実際に、コンパイルしてできたオブジェクトを逆アセンブルで確認するのが簡単でしょう。
確認するのが面倒であれば、「最適化オプション」としてgccやclangであれば、-O2, -O3 あたりを指定するのが簡単です。
インライン展開する関数は、展開先と同じソースに必要です。
ソースコード
/* * inline.c * Copyright (C) 2014 kaoru <kaoru@bsd> */ #include <stdio.h> #include <stdlib.h> inline static int max(int i1, int i2) { return (i1>i2) ? i1:i2; } int main(int argc, char *argv[]) { printf("%d\n", max(1,5)); exit(EXIT_SUCCESS); }
コンパイル
$ cc -O2 inline.c
実行例
$ ./a.out 5
実行例
staticを指定しないとコンパイルができないことがある
このようなコードは、Cコンパイラによってコンパイルエラーになります。
inline int max(int i1, int i2) { return (i1>i2) ? i1:i2; }
clang 3.3 では、以下の通りです。
$ cc -v FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610 Target: x86_64-unknown-freebsd10.0 Thread model: posix $ cc inline.c inline.c:(.text+0x25): undefined reference to `max' cc: error: linker command failed with exit code 1 (use -v to see invocation)
しかしながら、最適化オプションを追加すると問題がなくなります。
$ cc -O3 inline.c $
また、別の方法として、staticを指定します。
inline static int max(int i1, int i2) { return (i1>i2) ? i1:i2; }
インライン展開されていないケース
inlineを指定しても、Cコンパイラが独自判断し、インライン展開されないことがあります。 最適化レベルで決まるのかもしれません。
最適化オプションがデフォルトの場合です。
$ cc inline.c $ nm a.out |fgrep max 0000000000400760 t max $ gdb a.out GNU gdb 6.1.1 [FreeBSD] Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "amd64-marcel-freebsd"...(no debugging symbols found)... (gdb) disassemble main Dump of assembler code for function main: 0x0000000000400710 <main+0>: push %rbp 0x0000000000400711 <main+1>: mov %rsp,%rbp 0x0000000000400714 <main+4>: sub $0x20,%rsp 0x0000000000400718 <main+8>: mov $0x1,%eax 0x000000000040071d <main+13>: mov $0x5,%ecx 0x0000000000400722 <main+18>: movl $0x0,-0x4(%rbp) 0x0000000000400729 <main+25>: mov %edi,-0x8(%rbp) 0x000000000040072c <main+28>: mov %rsi,-0x10(%rbp) 0x0000000000400730 <main+32>: mov %eax,%edi 0x0000000000400732 <main+34>: mov %ecx,%esi 0x0000000000400734 <main+36>: callq 0x400760 <max> 0x0000000000400739 <main+41>: lea 0x4007d6,%rdi 0x0000000000400741 <main+49>: mov %eax,%esi 0x0000000000400743 <main+51>: mov $0x0,%al 0x0000000000400745 <main+53>: callq 0x40049c <printf@plt> 0x000000000040074a <main+58>: mov $0x0,%edi 0x000000000040074f <main+63>: mov %eax,-0x14(%rbp) 0x0000000000400752 <main+66>: callq 0x4004cc <exit@plt> 0x0000000000400757 <main+71>: nopw 0x0(%rax,%rax,1) End of assembler dump.
最適化レベルを2(-O2)にすると、シンボルテーブルからmaxが消え、アセンブラレベルでの呼び出しもなくなりました。
$ cc -O2 inline.c $ nm a.out |fgrep max $ gdb -q a.out (no debugging symbols found)...(gdb) disassemble main Dump of assembler code for function main: 0x0000000000400710 <main+0>: push %rbp 0x0000000000400711 <main+1>: mov %rsp,%rbp 0x0000000000400714 <main+4>: mov $0x400776,%edi 0x0000000000400719 <main+9>: mov $0x5,%esi 0x000000000040071e <main+14>: xor %al,%al 0x0000000000400720 <main+16>: callq 0x40049c <printf@plt> 0x0000000000400725 <main+21>: xor %edi,%edi 0x0000000000400727 <main+23>: callq 0x4004cc <exit@plt> 0x000000000040072c <main+28>: nop 0x000000000040072d <main+29>: nop 0x000000000040072e <main+30>: nop 0x000000000040072f <main+31>: nop End of assembler dump.
関連項目
ツイート
スポンサーリンク