在 C(++) 中优化远离函数表

Posted

技术标签:

【中文标题】在 C(++) 中优化远离函数表【英文标题】:Optimising away function table in C(++) 【发布时间】:2013-06-03 08:57:05 【问题描述】:

为了使程序的一部分易于单元测试,我想让它采用一个函数表,该表可以指向操作系统原语(即报告我们可以提供一组剪贴板目标的函数) 或测试版本。理想情况下,虽然我不希望在实时版本中有函数表的开销,但只是它借给代码的额外结构。所以我想用某种方式告诉编译器函数表永远不会改变,这样它就可以优化查找。像这样的东西(用于说明的简单实现):

#ifndef TEST
const
#endif
static struct 
    void (*reportTargets)(size_t targetc, const char **targetv);
    [...]
 interfaceToOutside
#ifndef TEST
= 
    reportTargetsLive,
    [...]

#endif
;

这可能会奏效吗?如果没有关于如何实现(或做得更好)的好建议?

【问题讨论】:

这是 C 还是 C++?如果是后者,那么您基本上是在描述虚函数,编译器通常非常擅长优化...... 我认为这不值得打扰,而且我不确定编译器是否会始终优化调用以避免间接调用(这在实践中可能无关紧要)。 Oli,我原以为虚函数的语义实际上阻止了编译器完全优化查找(例如,如果函数是合适的候选者,则内联)。编辑:也就是说,我总是可以#ifdef virtual 关键字。 Basile,我意识到收益通常是微乎其微的,我要求的兴趣与实用价值一样多。 我不会打扰#ifdefing 任何事情(除非分析器告诉我)。相反,我会为所需的操作系统功能使用带有虚拟功能的接口,并为您正在开发的操作系统和单元测试提供实现。这使得代码比#ifdefd 手写的vtables 更简洁,更易于维护。它提供了使用剪贴板服务的代码关注点与该服务的实现的清晰分离。作为奖励,它有助于以后移植到其他操作系统,您可以在其中提供接口的另一种实现。 【参考方案1】:

所以我想用某种方式告诉编译器函数表永远不会改变(...)

好吧,声明所有const(顺便说一句,你应该在staticstruct之间交错第一个const):

#ifndef TEST
# define CONST const
#else
# define CONST 
#endif

static CONST struct 
    void (*CONST reportTargets)(size_t targetc, const char **targetv);
    [...]
 interfaceToOutside
#ifndef TEST
= 
    reportTargetsLive,
    [...]

#endif
;

#undef CONST

(宏名不好,我知道)。

现在,

这可能会奏效吗(...)?

我想是这样,但您仍应检查生成的汇编代码(gcc/g++-S 选项)。

【讨论】:

【参考方案2】:

您可以使用静态内联函数创建 2 个结构,而不是函数指针。一个是测试用的,一个是真实的。现在,根据您实例化模板的方式,您要么处于测试模式,要么处于实时模式。

struct Live

    static void Report(const std::string& report)  ReportLive(report); 
;

struct Test

    static void Report(const std::string& report)  ReportTest(report); 
;

template<typename T>
class Reporter

public:
    void doReport()
    
        //some stuff todo
        T::Report(report);
        //other stuff todo
    
;

这只是一个想法。内联代码时,编译器将(完全)优化结构。此外,您可以通过实现不同的结构来选择不同的测试行为。

【讨论】:

以上是关于在 C(++) 中优化远离函数表的主要内容,如果未能解决你的问题,请参考以下文章

C 语言高效编程与代码优化

C 语言高效编程与代码优化

如何优化/改进此哈希函数

使用表函数优化多个连接

mysql-优化二

为大型 Postgresql 表优化嵌套连接窗口函数