帮助编译器优化函数指针

Met*_*tiu 19 c optimization gcc function-pointers linux-kernel

用C实施OO状代码封装和多态的一种常见的方法是不透明的指针返回到含有一些函数指针的结构.这是一个非常频繁的模式,例如在Linux内核中.

使用函数指针,而不是函数调用引入了开销,这是由于缓存大多可以忽略不计,因为已经在其他问题进行讨论.

但是,对于GCC(> 4.6)的新-fwhole-program和-flto优化选项,情况会发生变化.

libPointers.c

#include <stdlib.h>
#include "libPointers.h"

void do_work(struct worker *wrk, const int i) 
{
        wrk->datum += i;
}

struct worker *libPointers_init(const int startDatum)
{
        struct worker *wrk = malloc (sizeof (struct worker));

        *wrk = (struct worker) {
                .do_work = do_work,
                .datum = startDatum
        };

        return wrk;
}
Run Code Online (Sandbox Code Playgroud)

libPointers.h

#ifndef __LIBPOINTERS_H__
#define __LIBPOINTERS_H__


struct worker {
        int datum;

        void (*do_work)(struct worker *, int i);
};

extern void do_work (struct worker *elab, const int i);

struct worker *libPointers_init(const int startDatum);


#endif //__LIBPOINTERS_H__
Run Code Online (Sandbox Code Playgroud)

testPointers.c

#include <stdio.h>
#include "libPointers.h"


int main (void)
{
        unsigned long i;
        struct worker *wrk;

        wrk = libPointers_init(56);

        for (i = 0; i < 1e10; i++) {
#ifdef USE_POINTERS
                wrk->do_work(wrk,i);
#else
                do_work(wrk,i);
#endif
        }

        printf ("%d\n", wrk->datum);
}
Run Code Online (Sandbox Code Playgroud)

使用-O3进行编译,但没有-flto -fwhole节目标志,testPointers执行需要25秒左右我的机器上,USE_POINTERS无论已经#defined与否.

如果我打开-flto -fwhole-program标志,testPointers使用USE_POINTERS #defined需要大约25秒,但如果使用函数调用则需要大约14秒.

这是完全预期的行为,因为我理解编译器将内联并优化循环中的函数.但是,我想知道是否有一种方法可以帮助编译器告诉它函数指针是不变的,因此也允许它优化这种情况.

对于那些使用cmake的人来说,这就是我编译它的方式

的CMakeLists.txt

set (CMAKE_C_FLAGS "-O3 -fwhole-program -flto")
#set (CMAKE_C_FLAGS "-O3")
add_executable(testPointers
        libPointers.c
        testPointers.c
        )
Run Code Online (Sandbox Code Playgroud)

Mar*_*som 10

除非可以确定只调用该函数的一个可能版本,否则编译器不能内联函数.通过指针调用,这是非常明显的.编译器仍有可能弄明白,因为如果你遵循代码,指针只能有一个可能的值; 但是这超出了我对编译器的期望.