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

发布于 2024-10-10 23:14:28 字数 601 浏览 6 评论 0原文

// 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。
我不知道如何解决它。
是否可以?

// 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

I would like to inline the foo function only when I build for release. I don't want to inline functions for Debug build.

I tried it but linker errors annoyed me.
In this case, foo function's body is defined in common.h header file.
so if I just do

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

It will be met a link error in DEBUG build. Because two modules try to include common.h.
I have no idea to solve it.
Is it possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

别靠近我心 2024-10-17 23:14:28

“简单”的解决方案是这样的:

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

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

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

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

The "easy" solution would be this:

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

static is necessary to silence linking errors and get around the One Definition Rule.

A better solution would be to simply disable inlining project wide for debugging. GCC supports the -wno-inline-functions and -fno-inline-small-functions options to counteract those optimizations, and it also does not enable inlining for -O1 or lower (and probably -Os as well). Most compilers have similar options.

I call the latter a better solution because it should instruct the compiler to ignore the inline hint, eliminating the need for pesky preprocessor directives.

烟酉 2024-10-17 23:14:28

需要认识到的基本一点是,inline 关键字(或 Microsoft 的 C 语言 __inline 扩展 - 因为 MSVC 不支持 C99)本质上是违反单一定义规则的通行证。如果您考虑一下 - 这就是它的全部内容,因为编译器没有义务实际执行任何内联。

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

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

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

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

common.h 标头:
// 通用.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(视情况而定)。

如果您编译为非发布:

cl  test.c foo.c

您有一个非内联 foo()

编译器和链接器在这两种情况下都很满意。

话虽如此,我有点喜欢将 INLINE 重新定义为 static 以便进行调试的建议。

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

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

The fundamental thing to realize is that the inline keyword (or Microsoft's __inline extension for C - since MSVC doesn't support C99) is essentially a pass to violate the one definition rule. If you think about it - that's all it really is, since the compiler is under no obligation to actually perform any inlining.

So, when you have an inline function you're allowed to have the function defined in more than one module. In fact, you're obligated to have it defined in any module that actually uses the function.

However, if you don't declare the function as inline, you have to ensure that you have no more than one definition (exactly one if it actually gets used). For non-member functions (all function in C), there are a few ways around this:

  • declare the function as static to change it's linkage to internal (note that you can have static inline functions to begin with).
  • in C++ you can place them in an anonymous namespace (which has an effect similar to declaring the static)
  • you can use preprocessor manipulation to handle this. It's kind of ugly, but it works, and I've seen the technique used successfully in the wild. Whether it's worth the effort is another thing altogether - you'll have to decide that yourself.

Basically, what you need to do is have an implementation of the function in a separate .c file, just like if you were following the tradition of a-single-function-per-module coding standard (actually you can do this just as well putting several inline functions in the .c module - but they should all be inline or not inline as a group to keep things from getting too out of hand). The implementation of the function needs to arrange to be able to be included in a header - so it needs include guards, just like any other header. Then you use the preprocessor to conditionally include the implementation as part of the header when you want inline functions (so the implementation will be available to all modules), but don't include it if you're not inlining (so you follow the one definition rule in that case):

The common.h header:
// 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 */

The implementation of foo():

// foo.c
#ifndef FOO_C
#define FOO_C

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


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

#endif /* FOO_C */

And an example program:

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

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

Now if you compile for release:

cl /DRELEASE main.c foo.c

foo() will be inline (or __inline as the case may be).

If you compile for non-release:

cl  test.c foo.c

you have a non-inline foo().

And both the compiler and linker are happy in either case.

All that said, I kind of like the suggestion to maybe redefine INLINE to be static for debugging purposes.

However, ultimately I'm not sure I see the point to any of this really - modern debuggers are able to step through functions that are inline, and the debugger probably won't inline function calls if you disable optimizations. So you can set breakpoints inside the inline function as well and have it work fine in non-optimized builds.

I'm not sure exactly what you're end-goal in this really is. What's the drawback to leaving the functions as inline in debug/non-optimized builds?

失与倦" 2024-10-17 23:14:28

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

You can't declare header only functions as non-inline. You could declare them as static (a.k.a. C-style static), but that will generate a copy of the function (including local static variables, if any) in each translation unit. A better solution is to leave it as inline. In debug mode when optimizations are disabled compilers usually don't inline any functions.

送舟行 2024-10-17 23:14:28
#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。当然你可以从这里看到有很多方法可以做到。

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

Then

// 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

then define RELEASE for the release version. of course you can see from this there are lots of ways to do it.

鹿! 2024-10-17 23:14:28

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

更实用:

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

In most cases release flags are not defined. Typically debug flags are defined.
_DEBUG is defined by most compilers, so there is no need to define a release flag:

More practical:

#ifndef _DEBUG
    __inline void foo() { /* something */ }
#else 
     //some alternative
#endif
谎言月老 2024-10-17 23:14:28

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

示例:

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

Use compiler conditionals and define a compile time flag.

Example:

#ifdef RELEASE_BUILD_FLAG
  //Run inline function
#else
  //some alternative
#endif
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文