inline

提供: C言語入門
移動: 案内検索
スポンサーリンク

inline(インライン関数指示子) とは、高速化のために「関数」を明示的に「インライン展開」させるための「指示」を与えるものです。

読み方

inline
いんらいん
インライン関数指示子
いんらいん かんすう しじし

概要

「インライン展開」するメリットは、「高速化」です。「関数呼び出しのオーバーヘッド」をなくすことができます。 従来は、マクロで実装し、マクロが展開されることによって、高速化するという手法もありましたが、「マクロによる黒魔術」は、プログラマが予想しなかったコードを生み出し、「結果が異なる」現象を引き起こしやすい面があります。

Cコンパイラの「最適化レベル」を上げないと、「インライン展開」が実施されない可能性があります。 実際に、コンパイルしてできたオブジェクトを逆アセンブルで確認するのが簡単でしょう。

確認するのが面倒であれば、「最適化オプション」としてgccclangであれば、-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.

関連項目




スポンサーリンク