如何仅为发布版本内联函数

时间:2011-01-07 04:33:37

标签: c function inline c-preprocessor

// common.h
// This is foo function. It has a body.
__inline void foo() { /* something */ }

// a.cpp
#include "common.h" // for foo function
// Call foo

// b.cpp
#include "common.h" // for foo function
// Call foo

我想在我为发布版本构建时内联 foo 函数。我不想为Debug构建内联函数。

我试过了,但链接器错误让我感到恼火 在这种情况下,foo函数的主体在 common.h 头文件中定义 所以,如果我只是做

//common.h
#if !defined(_DEBUG)
__inline
#endif
void foo() { /* something */ }

DEBUG版本中会遇到链接错误。因为两个模块试图包含common.h 我不知道要解决它。
有可能吗?

6 个答案:

答案 0 :(得分:7)

“简单”解决方案就是:

#if !defined(_DEBUG) || defined(NDEBUG)
#define INLINE inline
#else
#define INLINE static
#endif

static对于消除链接错误和绕过单一定义规则是必要的。

更好的解决方案是简单地禁用内联项目进行调试。 GCC支持-wno-inline-functions-fno-inline-small-functions选项来抵消这些优化,并且启用-O1或更低版本(可能-Os以及)。大多数编译器都有类似的选项。

我将后者称为更好的解决方案,因为它应该指示编译器忽略inline提示,从而无需使用讨厌的预处理程序指令。

答案 1 :(得分:5)

要实现的基本要点是,inline关键字(或Microsoft的__inline扩展名为C - 因为MSVC不支持C99)本质上是违反一个定义规则的过程。如果你考虑一下 - 这就是它的全部,因为编译器没有义务实际执行任何内联。

因此,当您拥有inline函数时,您可以在多个模块中定义函数。事实上,您有义务在任何实际使用该功能的模块中定义它。

但是,如果您没有将该函数声明为inline,则必须确保您只有一个定义(如果它实际被使用,则只有一个)。对于非成员函数(C中的所有函数),有几种方法:

  • 将该函数声明为static以更改它与内部的链接(请注意,您可以开始使用static inline函数)。
  • 在C ++中,您可以将它们放在匿名命名空间中(其效果类似于声明静态)
  • 您可以使用预处理器操作来处理此问题。它有点难看,但它有效,而且我已经看到了在野外成功使用的技术。是否值得努力是另一回事 - 你必须自己决定。

基本上,你需要做的是在一个单独的.c文件中实现该函数,就像你遵循传统的单模函数编码标准(实际上你可以这样做)同样在.c模块中放置几个​​内联函数 - 但是它们都应该是内联的或不是内联的,以防止事情变得太失控。该函数的实现需要安排能够包含在标题中 - 因此它需要包括警卫,就像任何其他标题一样。然后,当您需要内联函数时,使用预处理器有条件地将实现作为标题的一部分包含在内(因此实现将可用于所有模块),但如果您没有内联,则不要包含它(因此,请遵循一个在那种情况下的定义规则):

common.h标题:     // common.h     #ifndef COMMON_H     #define COMMON_H

#ifdef RELEASE
#define USE_INLINE
#define INLINE __inline
#else
#define INLINE
#endif

INLINE void foo(void);
#ifdef USE_INLINE
#include "foo.c"
#endif

#endif /* COMMON_H */

foo()的实施:

// foo.c
#ifndef FOO_C
#define FOO_C

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


INLINE void foo()
{
    printf("foo\n");
}

#endif /* FOO_C */

一个示例程序:

// main.c
#include<stdio.h>
#include "common.h"

int main()
{
    foo();
    return 0;
}

现在,如果你为发布版编译:

cl /DRELEASE main.c foo.c

foo()将为inline(或__inline视情况而定)。

如果编译为非发行版:

cl  test.c foo.c

您有非内联foo()

无论是哪种情况,编译器和链接器都都很满意。

所有这一切,我都喜欢将INLINE重新定义为static以进行调试的建议。

然而,最终我不确定我是否真的看到了这一点 - 现代调试器能够逐步执行inline的函数,如果禁用调试器可能不会内联函数调用优化。因此,您也可以在内联函数中设置断点,并使其在非优化构建中正常工作。

我真的不确定你到底是什么目标。将函数inline保留在调试/非优化构建中有什么缺点?

答案 2 :(得分:4)

#ifdef RELEASE
#define INLINE __inline
#else
#define INLINE
#endif

然后

// common.h
INLINE void foo() { /* something */ }

// a.cpp
#include "common.h" // for foo function
// Call foo

// b.cpp
#include "common.h" // for foo function
// Call foo

然后为发布版本定义RELEASE。当然,你可以从中看到有很多方法可以做到。

答案 3 :(得分:3)

您不能将仅标题函数声明为非内联函数。您可以将它们声明为静态(a.k.a. C风格静态),但这将在每个转换单元中生成函数的副本(包括本地静态变量,如果有的话)。更好的解决方案是将其保留为内联。在调试模式下,当禁用优化时,编译器通常不会内联任何函数。

答案 4 :(得分:1)

在大多数情况下,未定义发布标志。通常定义调试标志。 _DEBUG由大多数编译器定义,因此无需定义发布标志:

更实用:

#ifndef _DEBUG
    __inline void foo() { /* something */ }
#else 
     //some alternative
#endif

答案 5 :(得分:0)

使用编译器条件并定义编译时标志。

示例:

#ifdef RELEASE_BUILD_FLAG
  //Run inline function
#else
  //some alternative
#endif