Inline In C99

Table of Contents

1. Inline In C99

1.1. The Problem

#include <stdio.h>

inline int foo() { return 0x64; }

int main() {
    printf("Output is: %d\n", foo());
    return 0;
}

Output is: 100

上面的代码使用 c99 且用 `-O2` 时可以编译过, 且 foo 被 inline. 但使用 `-O0` 则编译失败, 错误为 undefined reference to `foo`

1.2. 原因

针对 inline 关键字, c99 与 c89 的意义不同.

在 c89 中, inline 即 static inline, 通常的用法是把 static inline 定义的函数放在头文件中, 然后所有需要使用这个函数的 c 去 include 这个头文件.

1.2.1. 重复的 foo

static inline 是 internal linkage, 所以如果编译器没有成功 inline (例如使用了 -O0), 则每个编译单元中都会有一个 foo 的实现且 link 时不会出现 `multiple definition` 的错误.

inline 的好处是省去函数调用的开销,坏处是需要更多的代码,因为每个函数调用都会被展开。 但是在 c89 的情况下,若编译器没有成功 inline,则既没有节省函数调用开销,又需要更多的代码。

/* test.h */
static inline void foo() {}
/* a.c */
int main(int argc, char *argv[]) { foo(); }
/* test.h */
static inline void foo() {}
/* b.c */
void b() { foo(); }
gcc /tmp/a.o /tmp/b.o -o /tmp/a.out
objdump -d /tmp/a.out |grep \<foo\>: -A 5

0000000000001129 <foo>: 1129: 55 push %rbp 112a: 48 89 e5 mov %rsp,%rbp 112d: 90 nop 112e: 5d pop %rbp 112f: c3 retq – 0000000000001154 <foo>: 1154: 55 push %rbp 1155: 48 89 e5 mov %rsp,%rbp 1158: 90 nop 1159: 5d pop %rbp 115a: c3 retq

1.2.2. 不同的 foo

由存在多个重复的 foo, 所以这些 foo 的地址都是不同的,看起来会违反直觉

1.3. Inline In C99

C99 的 inline 是为了解决上面的两个问题

  1. 需要在共同的头文件中用 inline 定义 foo 函数,保证成功 inline 时编译器在各个编译单元都知道如何展开

    /* test.h */
    inline void foo() {}
    
  2. 在某一个编译单元里用 extern inline 声明一个 foo 函数,使得 inline 失败时都会 link 到这一个 foo 函数

    /* a.c */
    extern inline void foo();
    /* 或者用 void foo(); */
    

例如:

1.3.1. a.o 包含 foo 的实现

inline void foo() {}

extern inline void foo();
int main(int argc, char *argv[]) {
    foo();
    return 0;
}
readelf -a /tmp/a.o|grep foo

000000000024 000900000004 R_X86_64_PLT32 0000000000000000 foo - 4 9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 foo

1.3.2. b.o 不包含 foo 的实现

inline void foo() {}

void hello() { foo(); }
readelf -a /tmp/b.o|grep foo

00000000000e 000b00000004 R_X86_64_PLT32 0000000000000000 foo - 4 11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND foo

Author: [email protected]
Date: 2021-09-18 Sat 00:00
Last updated: 2023-02-24 Fri 19:44

知识共享许可协议