C 如何内联仅用于发布版本的函数

C 如何内联仅用于发布版本的函数,c,function,inline,c-preprocessor,C,Function,Inline,C Preprocessor,我只想在为发布版构建时内联foo函数。我不想为Debugbuild内联函数 我试过了,但链接器错误让我很恼火。 在这种情况下,foo函数的主体在common.h头文件中定义。 所以如果我这么做的话 // common.h // This is foo function. It has a body. __inline void foo() { /* something */ } // a.cpp #include "common.h" // for foo function // Call f

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

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

// 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
DEBUG
build中会遇到链接错误。因为两个模块试图包含common.h.
我没有办法解决它。

可能吗?

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

示例:

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


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

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

更实用:

// 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
“简单”的解决方案是:

#ifndef _DEBUG
    __inline void foo() { /* something */ }
#else 
     //some alternative
#endif
static
是消除链接错误和绕过一个定义规则所必需的

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


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

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

需要了解的基本情况是,
内联
关键字(或Microsoft的
\u内联
C扩展-因为MSVC不支持C99)本质上是违反一个定义规则的过程。如果你仔细想想,这就是它真正的意义所在,因为编译器没有义务实际执行任何内联

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

但是,如果不将函数声明为
内联
,则必须确保定义不超过一个(如果实际使用,则正好是一个)。对于非成员函数(C中的所有函数),有几种解决方法:

  • 将函数声明为
    static
    以将其链接更改为internal(请注意,您可以先使用
    static inline
    函数)
  • 在C++中,可以将它们放置在匿名命名空间中(其作用类似于声明静态)
  • 您可以使用预处理器操作来处理此问题。这有点难看,但它很管用,而且我在野外看到了这种技术的成功应用。这是否值得努力完全是另一回事——你必须自己决定
基本上,您需要做的是在一个单独的.c文件中实现该函数,就像遵循传统的单函数/模块编码标准一样(实际上,在.c模块中放置几个内联函数也可以做到这一点——但它们都应该作为一个组内联或不内联,以防止事情变得过于失控)。函数的实现需要进行安排,以便能够包含在标头中-因此它需要像任何其他标头一样包含卫士。然后,当您需要内联函数时,您可以使用预处理器有条件地将实现作为标头的一部分包含(这样实现将可用于所有模块),但如果您不是内联的,则不要包含它(因此在这种情况下遵循一个定义规则):

common.h
标题: //普通的 #共同的 #定义公共_H

#if !defined(_DEBUG) || defined(NDEBUG)
#define INLINE inline
#else
#define INLINE static
#endif
foo()
的实现:

foo()

如果编译为非发布:

cl /DRELEASE main.c foo.c
您有一个非内联的
foo()

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

尽管如此,出于调试目的,我还是有点喜欢将
INLINE
重新定义为
static

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


我不确定你的最终目标到底是什么。在调试/非优化构建中保留函数作为
内联
有什么缺点?

使用包含保护:#ifndef COMMON#define COMMON#define foo here#endifWhy Use
(内联
)为什么不使用
内联
(符合标准的一个)?任何一个好的编译器都有一个编译选项。不需要修改代码。禁止内联是/Ob0。@纳瓦兹:微软的编译器不支持C代码的C99,因此使用了
\uu inline
扩展。除非过去几年发生了变化,否则WDK(内核模式)几乎什么也做不了使用C++来做内联代码。当人类有99%的错误时,它是浪费时间。让编译器做它知道它什么时候和为什么做内衬,它将自动地在没有你帮助的情况下自动完成。
#if !defined(_DEBUG) || defined(NDEBUG)
#define INLINE inline
#else
#define INLINE static
#endif
#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.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
cl  test.c foo.c