C言語のinline関数指示子の使い方と実例を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
inline関数指示子
inline関数指示子は,C言語のC99規格から採用されたコンパイラに対して特定の関数をインライン展開するよう指示するものです.
つまり,コンパイラに対して,その関数を呼び出している全ての箇所に関数の実体を挿入するよう指示します.
inlineにより関数を呼び出す処理が不要になるため,処理時間が短くなるメリットがありますが,コードサイズが大きくなるデメリットがあります.
inlineはマクロ関数でも代用できますが,マクロの副作用により,想定と結果が異なる現象が発生する可能性があります.
なので,マクロ関数ではなくC言語の機能であるinlineを利用することが好ましいです.
マクロを知りたいあなたはこちらからどうぞ.
inline関数指示子の注意点として,inlineを関数に指示した場合でも,コンパイラの最適化レベルを上げないとインライン展開されないことがあります.
GCC/Clangでは最適化オプションを-O2以上に設定する方が無難です.
また,inlineを指示する関数が多すぎる場合は,インライン展開が失敗して通常の関数呼び出しになる可能性があります.
なので,本当に必要な関数のみinlineを指示した方が無難です.
実際に関数がインライン展開できたかどうか確認したい場合は,アセンブリ言語(x86-64)を読みましょう!
GCC/Clangでは,inlineキーワードの前にstaticを入れないとコンパイルが成功しないので注意して下さい.
なので,「static inline」とセットで使うことを覚えましょう!
参考までに,G++/Clang++/Visual StudioはC++言語のコンパイラなので,コンパイルが成功します.
inlineの使い方
inlineの使い方は以下になります.
square関数の定義の前に「static inline」とインライン展開を指示していることがわかります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> static inline int square(int n) { return n * n; } int main(void) { int n; printf("Please input an integer: "); scanf("%d", &n); printf("square(%d) = %d\n", n, square(n)); return 0; } |
実行結果は以下になります.
1 2 3 4 |
$ gcc inline.c $ a.out Please input an integer: 3 square(3) = 9 |
inline.cのアセンブリ言語(x86-64)の出力結果は以下になります.
以下の58行目でmain関数がsquare関数(6~20行目)を呼び出しているので,インライン展開されていないことがわかります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
$ gcc inline.c -S $ cat inline.s .file "inline.c" .text .type square, @function square: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl -4(%rbp), %eax imull %eax, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size square, .-square .section .rodata .LC0: .string "Please input an integer: " .LC1: .string "%d" .LC2: .string "square(%d) = %d\n" .text .globl main .type main, @function main: .LFB1: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax leaq .LC0(%rip), %rax movq %rax, %rdi movl $0, %eax call printf@PLT leaq -12(%rbp), %rax movq %rax, %rsi leaq .LC1(%rip), %rax movq %rax, %rdi movl $0, %eax call __isoc99_scanf@PLT movl -12(%rbp), %eax movl %eax, %edi call square movl %eax, %edx movl -12(%rbp), %eax movl %eax, %esi leaq .LC2(%rip), %rax movq %rax, %rdi movl $0, %eax call printf@PLT movl $0, %eax movq -8(%rbp), %rdx subq %fs:40, %rdx je .L5 call __stack_chk_fail@PLT .L5: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE1: .size main, .-main .ident "GCC: (Ubuntu 11.2.0-19ubuntu1) 11.2.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4: |
GCCに最適化オプション-O2をつけてコンパイルして,アセンブリ言語(x86-64)を出力します.
上記の結果と比較すると,square関数がインライン展開されてmain関数に挿入されていることがわかります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
$ gcc inline.c -O2 -S $ cat inline.s .file "inline.c" .text .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "Please input an integer: " .LC1: .string "%d" .LC2: .string "square(%d) = %d\n" .section .text.startup,"ax",@progbits .p2align 4 .globl main .type main, @function main: .LFB24: .cfi_startproc endbr64 subq $24, %rsp .cfi_def_cfa_offset 32 leaq .LC0(%rip), %rsi movl $1, %edi movq %fs:40, %rax movq %rax, 8(%rsp) xorl %eax, %eax call __printf_chk@PLT leaq 4(%rsp), %rsi leaq .LC1(%rip), %rdi xorl %eax, %eax call __isoc99_scanf@PLT movl 4(%rsp), %edx xorl %eax, %eax movl $1, %edi leaq .LC2(%rip), %rsi movl %edx, %ecx imull %edx, %ecx call __printf_chk@PLT movq 8(%rsp), %rax subq %fs:40, %rax jne .L5 xorl %eax, %eax addq $24, %rsp .cfi_remember_state .cfi_def_cfa_offset 8 ret .L5: .cfi_restore_state call __stack_chk_fail@PLT .cfi_endproc .LFE24: .size main, .-main .ident "GCC: (Ubuntu 11.2.0-19ubuntu1) 11.2.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4: |
inlineのLinuxカーネルにおける実例
inlineのLinuxカーネルにおける実例を紹介します.
Linuxカーネルでは,inlineは__always_inlineマクロとして利用されています.
__always_inlineマクロは,GCC/Clangの拡張機能を利用した「inline __attribute__((__always_inline__))」として定義されています.
include/linux/spinlock.hにあるspinlock_check関数では,「static __always_inline」という形で利用されてています.
スピンロック処理はLinuxカーネルでよく利用されるので,高速化したいからですね.
1 2 3 4 |
static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) { return &lock->rlock; } |
Linuxカーネルを学びたいあなたはこちらからどうぞ.
まとめ
C言語のinline関数指示子と,その使い方を紹介しました.
また,inlineのLinuxカーネルにおける実例を解説しました.
同じ関数指示子の_Noreturnを知りたいあなたはこちらからどうぞ.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!