V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
villivateur
V2EX  ›  C

C 语言里面的 inline 关键字到底是啥意思?

  •  
  •   villivateur · 2021-08-12 12:26:41 +08:00 · 3757 次点击
    这是一个创建于 1203 天前的主题,其中的信息可能已经有所发展或是发生改变。

    起因是我突然发现用 GCC 不带任何编译选项来编译下面的 C 代码,会报错:

    #include <stdio.h>
    
    inline void func()
    {
            printf("Hello world!\n");
    }
    
    int main()
    {
            func();
            return 0;
    }
    

    错误输出:

    /usr/bin/ld: /tmp/ccdw5O1b.o: in function `main':
    test.c:(.text+0xe): undefined reference to `func'
    collect2: error: ld returned 1 exit status
    

    但是,用 G++ 不带任何编译选项编译下面的 C++ 代码,正常运行:

    #include <iostream>
    
    using namespace std;
    
    inline void func()
    {
            cout << "Hello world!" << endl;
    }
    
    int main()
    {
            func();
            return 0;
    }
    

    我把 C 代码中的 func 加上 static 修饰符,可以正常编译:

    #include <stdio.h>
    
    static inline void func()
    {
            printf("Hello world!\n");
    }
    
    int main()
    {
            func();
            return 0;
    }
    

    用 inline 声明 func 也可以正常编译:

    #include <stdio.h>
    
    inline void func();
    
    void func()
    {
            printf("Hello world!\n");
    }
    
    int main()
    {
            func();
            return 0;
    }
    

    编译的时候加上 -O2 选项也能正常编译。

    我查了很多的博客,包括 C11 的标准文件,但是迫于理解能力,还是没能搞懂为啥会这样,所以在此请教一下大家。

    附上我查的资料链接:

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

    https://stackoverflow.com/questions/19068705/undefined-reference-when-calling-inline-function

    https://stackoverflow.com/questions/16245521/c99-inline-function-in-c-file/16245669#16245669

    https://stackoverflow.com/questions/7762731/whats-the-difference-between-static-and-static-inline-function

    https://runtimeverification.com/blog/undefined-c-common-mistakes/

    17 条回复    2021-09-27 17:09:32 +08:00
    philon
        1
    philon  
       2021-08-12 13:35:44 +08:00
    inline 是某个内敛函数的“**定义**”,而非“**声明**”!(这种错误主要出现在高版本的 gcc 编译器中)
    简而言之,你突然在 main 里调用了一个未知的函数,所以报错了。试着在调用前将函数声明一下,比如:
    ```c
    #include <stdio.h>

    void func()
    inline void func()
    {
    printf("Hello world!\n");
    }

    int main()
    {
    func();
    return 0;
    }
    ```
    besto
        2
    besto  
       2021-08-12 14:07:38 +08:00
    1L 正解,另外你 Google 一下 C inline 就能得到结果了:https://stackoverflow.com/questions/31108159/what-is-the-use-of-the-inline-keyword-in-c/31108614
    wangxn
        3
    wangxn  
       2021-08-12 14:11:47 +08:00
    看来 C 和 C++还是有很多细微的区别。
    villivateur
        4
    villivateur  
    OP
       2021-08-12 14:14:26 +08:00 via Android
    @philon 有没有说反?是“声明”而非“定义”?
    xingheng
        5
    xingheng  
       2021-08-12 14:27:41 +08:00
    内联函数,不会压栈,编译的时候会被直接展开。
    villivateur
        6
    villivateur  
    OP
       2021-08-12 14:32:54 +08:00 via Android
    @xingheng 不要只看标题,麻烦看一下我的内容
    fullpowers
        7
    fullpowers  
       2021-08-12 14:34:20 +08:00
    C 的函数定义前需要声明,我觉得应该是这个原因
    aneostart173
        8
    aneostart173  
       2021-08-12 14:56:30 +08:00   ❤️ 3
    inline 在现代编译器里几乎没有任何作用。
    gabon
        9
    gabon  
       2021-08-12 18:44:12 +08:00 via Android
    是树莓派 tg 群里的吗,昨天刚好看到有人在问😂
    philon
        10
    philon  
       2021-08-12 19:10:06 +08:00   ❤️ 1
    @villivateur 对于我这种 CET-4 都没过的人来说,想要区分`declare`和`define`还是很有挑战性的哈😂

    我只是非常肤浅地以为,inline 是通知编译器要展开这段代码,但它因为没找到声明的地方就略过了,到了链接器的时候一看找不到函数原型,就抛了个`undefined reference`
    sosilver
        11
    sosilver  
       2021-08-12 20:39:11 +08:00 via Android   ❤️ 1
    看 modern c 写的,
    1. inline 放到函数定义上(要 inline 需要知道函数怎么实现的),一般在头文件里。
    2. 默认不会生成符号(不然多次包含会被重复定义)。
    3. 需要在一个 TU 里不带 inline 声明以生成符号。
    (括号内只是我的理解)
    dontmind
        12
    dontmind  
       2021-08-12 23:11:59 +08:00
    inline 是 c++ 先有,后来才引进 c,因为相容性问题才变了现在这样

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n633.htm
    >While the GCC-2.6.3 inlining facility was almost certainly modeled on the
    C++ inline capability there are several differences.

    ....

    >Much of this control is probably provided to get around the fact that the
    >loader won't collapse multiple definitions of a function to a single
    >instance as is done for uninitialized variables with external linkage.
    Huelse
        13
    Huelse  
       2021-08-13 01:05:16 +08:00
    我一直以为的是 inline 函数会被编译进调用的位置,现代编译器会判断 inline 声明的函数实现,过于复杂的话还是像其他普通函数一样进栈地址,另外 inline 可以被声明并在头文件中实现,如有错误欢迎指正~
    hobochen
        14
    hobochen  
       2021-08-13 19:54:26 +08:00
    @aneostart173 你说的几乎是指 10%以下的性能差异不算性能差异?
    muzuiget
        15
    muzuiget  
       2021-08-14 19:04:33 +08:00
    怎么我觉得第一个例子也应该算是合法,编译器能判断上下文吧。
    hxndg
        16
    hxndg  
       2021-08-27 12:41:57 +08:00
    gcc 4.8.5 没发现这个问题
    gcc 4.9.2 没发现这个问题
    gcc 5.3.1 发现确实存在这个问题

    然后有几个小细节需要注意下:
    1 inline 是建议,不是必然展开
    2 如果你把 inline 放到 main 函数后面就会报几个 warning,但是能正常编译,编译器会 implicit declaration of function ‘func’
    3 inline 在前面的话,gcc -c main.c 生成的 main.o 会发现找不到 func 的定义。具体原因我就不知道了。。。
    4 不要自己去给编译器的行为找合理解释。。。因为很可能解释是错的。。。。
    zeroxia
        17
    zeroxia  
       2021-09-27 17:09:32 +08:00
    程序员就是喜欢谁也看不起谁。本来 C 也是从 C++那边抄过来的,非又搞的和 C++不一样。
    就好像理想的情况下,C++就是 C 的超集,这个世界就多简单,结果现在搞成这样。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2807 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:14 · PVG 23:14 · LAX 07:14 · JFK 10:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.