内联函数(inline function)

inline

  • 使用 inline 修饰函数的声明或者实现,可以使其变为联函数
    • 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用

特点

优点

  • 编译器会将函数调用直接展开为函数体代码
  • 可以减少函数调用的开销
  • 对于存取函数以及其它函数体比较短, 性能关键的函数, 建议使用内联.
  • 所以可以认为是 空间换时间思想的体现

缺点

  • 会增加代码体积

注意

  • 尽量不要内联超过 10 行代码的函数
  • 有些函数即使声明为 inline. 也不一定会被编译器内联,比如递归函数

内联函数与宏定义

  • 内敛函数,都可以减少函数调用的开销
  • 对比内敛函数多了语法检测和函数的特性

iOS中 inline 函数的使用

CG_INLINE

1
2
3
4
5
6
7
8
CG_INLINE CGRect
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
  CGRect rect;
  rect.origin.x = x; rect.origin.y = y;
  rect.size.width = width; rect.size.height = height;
  return rect;
}

// 这会使编译器为内联函数创建代码。而不是在堆栈上创建一个函数调用

以下引用来自 Stack Overflow 解释

CG_INLINE is a #define for static inline. This causes the compiler to create the code for the function inline, rather that creating a function call on the stack. See here and here for more information.

CG_INLINE is a macro that is used to mark a method as an inline function. The exact syntax is (was ?) compiler dependent, and through preprocessor checks the correct one is chosen for your compiler.

For current GCCs, it should resolve to static inline.

The point of a function marked with inline is that the compiler may insert the equivalent of that function’s body where the function was called, instead of making a (slightly more costly) function call. So if you have:

1
2
3
4
5
6
7
8
9
inline int foo(int a, int b)
{
   return a + b;
}

void bar(int a, int b)
{
   NSLog(@"%d", foo(a, b));
}

The compile then is allowed to internally transform it to:

1
2
3
4
void bar(int a, int b)
{
   NSLog(@"%d", a + b);
}

This saves a function call which on some architectures might be costly and might be very noticeable for example when you’re calling the function in a loop a few thousand times.

Note that it only means the compiler may do this transformation, it doesn’t necessarily mean it does do it. Depends on compiler settings.

三方库

比如 YYText 中内联函数的使用

1
2
3
4
5
static inline CGSize YYTextClipCGSize(CGSize size) {
    if (size.width > YYTextContainerMaxSize.width) size.width = YYTextContainerMaxSize.width;
    if (size.height > YYTextContainerMaxSize.height) size.height = YYTextContainerMaxSize.height;
    return size;
}