Understanding Inline Functions in C
Although C programming is considered a low-level programming language, the C code itself is not what is executed by the processor. What gets executed are the sets of instructions, known as opcodes, which are loaded into the hardware memory in binary format (a sequence of 0s and 1s).
The C compiler handles the translation of C code into a set of instructions that the processor can understand and execute. During different compilation stages, the compiler may introduce optimizations, which can result in some divergence between the written C code and what gets executed.
These optimizations are generally used to favor either overall performance (execution time) or to optimize the resulting code size, a concept known as the space-time trade-off.
An inline function is one performance optimization technique used by the compiler to eliminate the overhead associated with function calls.

Inline Keyword
The inline keyword is used with functions in C (it can also be used in C++, but here we focus on C programming) to mark a function as inline. This prevents the compiler from inserting the usual calling procedure required to invoke a function within the caller routine. Instead, the assembly code of the called inline function is integrated directly into the caller's assembly code.
Inline Function C Syntax
To define a function as inline, you need to:
- Mark the function declaration as
static inline. - Mark the function definition as
static inlineas well.
inline int example(void); // function declaration as inline
inline int example(void) // function definition marked with inline
{
return 10;
}
Note: The usage of the inline keyword and its expected impact may vary from one compiler to another. For GCC-based compilers (such as arm-none-eabi-gcc), you need to enable optimization with -O2 to achieve expected inline behavior.
Function Inline Impact and Example Code
Without Inline Keyword
#include <stdio.h>
#include <stdint.h>
int func(void);
int func(void)
{
return 10;
}
int main(void)
{
func();
return 0;
}
Assembly output without inline keyword (compiled for ARM Cortex-M3 using arm-none-eabi-gcc):
inline_example.o: file format elf32-littlearm
Disassembly of section .text:00000000 <func>:
0: b480 push {r7}
2: af00 add r7, sp, #0
4: 230a movs r3, #10
6: 4618 mov r0, r3
8: 46bd mov sp, r7
a: bc80 pop {r7}
c: 4770 bx lr
0000000e <main>:
e: b580 push {r7, lr}
10: af00 add r7, sp, #0
12: f7ff fffe bl 0 <func>
16: 2300 movs r3, #0
18: 4618 mov r0, r3
1a: bd80 pop {r7, pc}
With Inline Keyword
#include <stdio.h>
#include <stdint.h>
inline int func(void);
inline int func(void)
{
return 10;
}
int main(void)
{
func();
return 0;
}
Assembly output with inline keyword (compiled with optimization -O2):
inline_example.o: file format elf32-littlearm
Disassembly of section .text.startup:00000000 <main>:
0: 200a movs r0, #10
2: 4770 bx lr
The compiler eliminates the calling procedure and integrates the inline function's assembly code directly into the caller.
Calling Inline Function from Multiple Locations
#include <stdio.h>
#include <stdint.h>
inline int func(void);
int sum(int arg);
inline int func(void)
{
return 10;
}
int sum(int arg)
{
int tmp = 0;
tmp = func() + arg;
return tmp;
}
int main(void)
{
int result = 0;
result = func() + sum(8);
return result;
}
Assembly output with inline function called multiple times:
inline_example.o: file format elf32-littlearm
Disassembly of section .text:00000000 <sum>:
0: 300a adds r0, #10
2: 4770 bx lr
Disassembly of section .text.startup:00000000 <main>:
0: 201c movs r0, #28
2: 4770 bx lr
The inline function is inlined at all locations where it is invoked. Being marked static, it cannot be externalized to other C source files.
Compiler Commands
Build code with ARM GCC:
arm-none-eabi-gcc -mcpu=cortex-m3 -std=c99 -c -O0 inline_example.c -o inline_example.o
Generate disassembly:
arm-none-eabi-objdump -D inline_example.o > inline_example.disasm
Inline Function Main Purpose
1. Performance Optimization
Eliminates the overhead associated with calling and returning from a function, affecting both caller and callee sub-routines.
Caller sub-routine:
- Preparing input parameters
- Handling many parameters (stack usage)
- Branch instructions to function
Callee sub-routine:
- Prologue sequence (saving CPU registers)
- Epilogue sequence (returning to caller)
Interaction with external stack memory incurs timing penalties (tens to hundreds of CPU cycles).
2. Defining Inline Function in Header File
Defining inline functions in header files included in multiple C files can lead to linking errors. The inline keyword allows the compiler to insert the function directly at each call site, avoiding multiple definition errors.
3. Are Inline Functions Worth It?
Performance: Modern CPUs have optimized calling conventions, minimizing timing impact. ARM Cortex-M CPUs use registers (r0–r3) for most parameters.
Code Size: Small inline functions can reduce code size, but large functions increase overall code size due to replication.
Coding Restriction: static inline limits usage to the translation unit.
Conclusion
Use inline functions based on your specific use case. For small functions in single source files or when hardware latency is significant, inlining can improve performance. Otherwise, the benefits may not outweigh increased code size or restrictions.