ソースコードを見ていると、たまに出てくるのがインライン関数。
インライン関数を意識してソースコードを書くことはありませんが、知識としては持っておくべきだと思います。知らないとデバッグの時に困るかも。。
なのでマクロ関数との違いも含めて、インライン関数について説明していきます!
インライン関数とは?
インライン関数とは、関数をインライン化することによって、関数の処理を直接処理の中にソース展開することができる、というものです。
関数の先頭に、inline修飾子を付ければインライン関数になります。
1 2 3 4 |
inline void test_func(void) { /* 何かしらの処理 */ } |
関数を呼び出すときに、関数の処理に飛ぶまでに実は少し時間がかかっています。関数を呼び出すまでにかかる時間のことを、「関数のオーバーヘッド」と言います。
関数の呼び出しでそこまで大きな時間がかかるわけではないですが、たとえば以下のようにループ処理で関数を何度も呼び出すと、全体の処理時間が遅くなる場合があります。
1 2 3 4 5 6 7 8 9 |
for(i=0; i < 1000; i++) { func_print(); } void func_print() { printf("Hello World!\n"); } |
この例だと、func_print関数を1000回呼び出すのですが、その分関数の呼び出しに時間がかかってしまいます。
これに対し、func_printをインライン関数にすると、コンパイル後以下のようなソースコードに変わります。
1 2 3 4 5 6 7 8 9 |
for(i=0; i < 1000; i++) { printf("Hello World!\n"); //func_print()の処理がインライン展開される } inline void func_print() { printf("Hello World!\n"); } |
上記のように、func_print関数の呼び出し部分が変化して、func_print関数の中身の処理に置き換わりました。
これによって、関数呼び出しにかかる時間が無くなったので、処理速度が向上するようになります。
マクロ関数とは?
マクロ関数とは、define定義で使用するマクロを関数のように使用できる機能のことです。
1 2 3 4 5 6 7 8 9 10 |
#define ADD_NUM(a,b) a + b int main(void) { int aaa; aaa = ADD_NUM(2,3) ; printf("aaa...%d\n",aaa); return 0; } |
出力結果
aaa…5
define定義を学ぶときに一緒にマクロ関数も学ぶと思うので、知っている人も多いと思うので、詳しい説明は省略します。
マクロ関数を使うと、インライン関数同様に、コンパイル時にマクロに書かれた処理がコードとして展開されるので、関数を呼び出すまでの時間が無くなります。
なので個人的には、マクロ関数とインライン関数のメリットは同じだと思っています。
インライン関数とマクロ関数の違い
「インライン関数とマクロ関数をどう使い分けるの?」
と、疑問に思いますよね。
正直コードを書くとき、マクロ関数は使うことがありますが、わざわざインライン関数を使うことは少ないので、使い分けについては気にしなくて良いと思います。
ただ強いて言うなら、短めの処理はマクロ関数で、長い複雑な処理であればインライン関数、という使い分けで良いと思っています。
というのも、マクロ関数は1行で書けるシンプルな処理が好まれます。マクロ関数で改行をしたいときはバックスラッシュ(\)を付けることで何行かに分けて書くことも出来ますが、可読性がどんどん下がっていきます。
1 2 3 4 5 6 7 8 9 |
#define HIKIZAN_NUM(a,b) \ if(a <= b) \ { \ b - a; \ } \ else \ { \ a - b; \ } |
この程度であれば読めますが、個人的にはバックスラッシュ(\)が気になるな。。と感じます。
なのでもし使い分けるとすれば、簡素な処理はマクロ関数、複雑な処理はインライン関数で分けるのが良いのかなと思います。
最後に
ぼくが新人の頃、エミュレーターでデバッグをしていたのですが、そのときに関数にブレークポイントを貼れないことがありました。
そして色々調べているうちに、その関数がインライン関数になっていたんですね。インライン展開されてインライン関数はいないことになるので、そりゃブレークポイントを貼れないわけです。
といった感じで、インライン関数を書くことは無くても見かけることはあると思うので、知識はおさえておきましょう!