C 如果使用内联,速度增加多少?

C 如果使用内联,速度增加多少?,c,linux,gcc,C,Linux,Gcc,在我看来,内联可以加速代码执行,是吗 我们能从中获得多少速度?来自: 有时是,有时不是。也许吧 没有简单的答案。内联函数可能使代码更快,也可能使代码更慢。它们可能使可执行文件变大,也可能使其变小。他们可能会导致殴打,他们可能会阻止殴打。它们可能,而且常常,与速度完全无关 内联函数可能会使其更快:如图所示,过程集成可能会删除大量不必要的指令,从而使运行速度更快 内联函数可能会使速度变慢:内联太多可能会导致代码膨胀,这可能会导致按需分页虚拟内存系统的“震荡”。换句话说,如果可执行文件太大,系统可能会

在我看来,内联可以加速代码执行,是吗

我们能从中获得多少速度?

来自:

有时是,有时不是。也许吧

没有简单的答案。内联函数可能使代码更快,也可能使代码更慢。它们可能使可执行文件变大,也可能使其变小。他们可能会导致殴打,他们可能会阻止殴打。它们可能,而且常常,与速度完全无关

内联函数可能会使其更快:如图所示,过程集成可能会删除大量不必要的指令,从而使运行速度更快

内联函数可能会使速度变慢:内联太多可能会导致代码膨胀,这可能会导致按需分页虚拟内存系统的“震荡”。换句话说,如果可执行文件太大,系统可能会将大部分时间花在磁盘上获取下一段代码

内联函数可能会使其变大:这是代码膨胀的概念,如上所述。例如,如果一个系统有100个内联函数,每个内联函数扩展到100字节的可执行代码,并在100个位置被调用,则增加1MB。1MB会引起问题吗?谁知道呢,但最后的1MB可能会导致系统“颠簸”,从而减慢速度

内联函数可能会使它变小:编译器通常会生成比内联扩展函数体更多的代码来推送/弹出寄存器/参数。这种情况发生在非常小的函数中,当优化器能够通过过程集成删除大量冗余代码时,也就是说,当优化器能够使大函数变小时,这种情况也会发生在大函数中

内联函数可能会导致抖动:内联可能会增加二进制可执行文件的大小,这可能会导致抖动

内联函数可能会防止抖动:即使可执行文件大小增加,工作集大小(一次需要在内存中的页数)也可能会减小。当f()调用g()时,代码通常位于两个不同的页面上;当编译器按程序将g()的代码集成到f()中时,代码通常位于同一页上

内联函数可能会增加缓存未命中的数量:内联可能会导致内部循环跨越内存缓存的多行,这可能会导致内存缓存抖动

内联函数可能会减少缓存未命中的数量:内联通常会改进二进制代码中引用的局部性,这可能会减少存储内部循环代码所需的缓存线数量。这最终可能会导致CPU受限的应用程序运行得更快

内联函数可能与速度无关:大多数系统不受CPU限制。大多数系统都是I/O绑定、数据库绑定或网络绑定,这意味着系统整体性能的瓶颈是文件系统、数据库或网络。除非你的“CPU表”设定为100%,否则内联函数可能不会让你的系统更快。(即使在CPU受限的系统中,内联也只有在瓶颈本身中使用时才有帮助,而瓶颈通常只出现在代码的一小部分中。)

没有简单的答案:你必须用它来看看什么是最好的。不要满足于简单的回答,如“永远不要使用内联函数”或“始终使用内联函数”或“当且仅当函数少于N行代码时才使用内联函数”。这些一刀切的规则可能很容易写下来,但它们会产生次优结果


版权所有(C)Marshall Cline

使用
内联
使系统使用,但不保证始终使用。如果使用此选项,生成的代码将更长,可能更快,但如果某些优化处于活动状态,则替代模型并非总是更快。

我使用
内联
函数说明符(特别是
静态内联
)的原因不是因为“速度”,而是因为

  • static
    part告诉编译器该函数仅在当前翻译单元(正在编译的当前文件和包含的头文件)中可见

  • inline
    part告诉编译器,如果需要,它可以在调用站点包含函数的实现

  • 静态内联
    告诉编译器,如果在当前翻译单元中根本不使用该函数,它可以完全跳过该函数

    (具体地说,我使用最多的编译器和我使用最多的选项,
    gcc-Wall
    ,在标记为
    static
    的函数未使用时发出警告;但在标记为
    static inline
    的函数未使用时不会发出警告。)

  • 静态内联
    告诉我们,该函数是一个类似于宏的辅助函数,此外,还将类型检查器添加到与宏相同的行为中

  • 因此,在我看来,
    inline
    与速度本身有关的假设是不正确的。用直截了当的回答回答所陈述的问题会产生误导


    在我的代码中,您可以看到它们与一些数据结构关联,或者偶尔与全局变量关联

    一个典型的例子是,我想在自己的C代码中实现:

    #include <inttypes.h>
    
    static uint64_t  prng_state = 1; /* Any nonzero uint64_t seed is okay */
    
    static inline uint64_t  prng_u64(void)
    {
        uint64_t  state;
    
        state = prng_state;
        state ^= state >> 12;
        state ^= state << 25;
        state ^= state >> 27;
        prng_state = state;
    
        return state * UINT64_C(2685821657736338717);
    }
    
    该头文件定义了一些有用的助手函数,并声明了将在单独的.c文件中实现的函数
    grid\u create()
    grid\u load()
    grid\u save()

    (是的,这三个函数也可以在头文件中实现,但它会使头文件变得相当大
    #ifndef   GRID_H
    #define   GRID_H
    #include <stdlib.h>
    
    typedef struct {
        int            rows;
        int            cols;
        unsigned char *cell;
    } grid;
    #define  GRID_INIT { 0, 0, NULL }
    
    #define  GRID_OUTSIDE -1
    
    static inline int grid_get(grid *const g, const int row, const int col)
    {
        if (!g || row < 0 || col < 0 || row >= g->rows || col >= g->cols)
            return GRID_OUTSIDE;
        return g->cell[row * (size_t)(g->cols) + col];
    }
    
    static inline int grid_set(grid *const g, const int row, const int col,
                               const unsigned char value)
    {
        if (!g || row < 0 || col < 0 || row >= g->rows || col >= g->cols)
            return GRID_OUTSIDE;
        return g->cell[row * (size_t)(g->cols) + col] = value;
    }
    
    static inline void grid_init(grid *g)
    {
        g->rows = 0;
        g->cols = 0;
        g->cell = NULL;
    }
    
    static inline void grid_free(grid *g)
    {
        free(g->cell);
        g->rows = 0;
        g->cols = 0;
        g->cell = NULL;
    }
    
    int grid_create(grid *g, const int rows, const int cols,
                    const unsigned char initial_value);
    
    int grid_load(grid *g, FILE *handle);
    
    int grid_save(grid *g, FILE *handle);
    
    #endif /* GRID_H */