inline 和#define 在实践中有何区别?
正如标题所说; inline 关键字和 #define 预处理器指令在实践中有何区别?
As the title says; what's the difference in practice between the inline keyword and the #define preprocessor directive?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
类似函数的宏在定义它们的地方为您提供绝对零的健全性检查。当你搞砸了一个宏时,它会在一个地方工作正常,但在其他地方就坏了,直到你失去了几个小时的工作/睡眠时间,你才会知道为什么。类似函数的宏不对数据进行操作,而是对源代码进行操作。有时这很好,例如当您想要使用 FILE 和 LINE 内置函数的可重用调试语句时,但大多数时候,使用内联也可以完成函数,就像任何其他函数一样,在定义时检查语法。
Function-like macros give you absolutely zero sanity checking at the place where they're defined. When you screw up with a macro, it'll work fine in one place and be broken somewhere else, and you won't know why until you've lost several hours of work/sleep time. Function-like macros do not operate on data, they operate on source code. Sometimes this is good, for example when you want reusable debug statements that use FILE and LINE builtins, but most of the time, it can be done just as well with an inline function, which is checked for syntax at the point of definition just like any other function.
嗯,多行
#define
比内联函数更难编写和编辑。您可以像任何普通函数一样定义内联函数,并且可以毫无问题地定义变量。想象一下,您想在另一个函数中多次调用代码块,并且该代码块需要自己的变量:使用内联函数更容易(是的,您可以使用 #defines 和do { .. . } while (0);
但这是你必须考虑的事情)。另外,通过启用调试,您通常会获得内联函数的“模拟”堆栈框架,这有时可能会使调试更容易(至少这是当您使用 gcc 的
-g
进行编译/链接并调试时获得的结果)与 GDB、IIRC)。您可以在内联函数中放置断点。除此之外,结果应该几乎相同,AFAIK。
Well, a multi-line
#define
is harder to write and edit than an inline function. You can define an inline function just like any normal function and can define variables without problems. Imagine that you want to call a code-block several times within another function, and that code block needs its own variables: it's easier to do with inline functions (yes, you can do so with #defines anddo { ... } while (0);
but it's something you have to think about).Also, with enabled debugging, you normally get a "simulated" stack-frame for inline functions which might make debugging easier sometimes (at least that's what you get when you compile/link with gcc's
-g
and debug with GDB, IIRC). You can place breakpoints inside your inline'd function.Apart from that the result should be almost identical, AFAIK.
宏(用
#define
创建)总是按编写的方式替换,并且可能存在双重计算问题。另一方面,内联纯粹是建议性的 - 编译器可以随意忽略它。在 C99 标准下,内联函数还可以具有外部链接,创建可以链接的函数定义。
Macros (created with
#define
) are always replaced as written, and can have double-evaluation problems.inline
on the other hand, is purely advisory - the compiler is free to ignore it. Under the C99 standard, aninline
function can also have external linkage, creating a function definition which can be linked against.函数(无论
内联
与否)和宏实现不同的目的。他们的差异不应被视为意识形态,而更重要的是,他们可以很好地合作。宏是在编译时完成的文本替换,它们可以执行诸如
为您提供整数类型是否有符号的编译时表达式之类的操作。也就是说,当表达式的类型未知(在定义处)并且您想要对其执行某些操作时,理想情况下使用它们。另一方面,宏的陷阱是它们的参数可能会被计算多次,这由于副作用而很糟糕。
另一方面,函数(
内联
)是类型化的,这使得它们更加严格,或者用消极的措辞来说,灵活性较差。考虑函数第一个为无符号整数类型实现了简单的
abs
函数。第二个将其实现为有符号类型。 (是的,它需要一个无符号作为参数,这是为了目的。)我们可以将它们与任何整型类型一起使用。但是,返回类型始终是最大宽度,并且知道如何在两者之间进行选择存在一定的困难。
现在,通过以下宏,
我们已经实现了一系列
编译器将创建最佳代码
(好吧,我承认使用
abs
这样做有点人为,但我希望您能明白。)Functions (whether
inline
or not) and macros fulfill different purposes. Their difference should not be seen as ideological as some seem to take it, and what is even more important, they may work nicely together.Macros are text replacement that is done at compile time and they can do things like
which gives you a compile time expression of whether or not an integral type is signed or not. That is, they are ideally used when the type of an expression is not known (at the definition) and you want to do something about it. On the other hand, the pitfall with macros is that their arguments may be evaluated several times, which is bad because of side effects.
Functions (
inline
) on the other are typed, which makes them more strict or, phrased negatively, less flexible. Consider the functionsThe first implements the trivial
abs
function for an unsigned integral type. The second implements it for a signed type. (yes, it takes an unsigned as argument, this is for purpose.)We may use these with any integral type. But, the return type will always be of the largest width and there is a certain difficulty on knowing how do choose between the two.
Now with the following macro
we have implemented a
compiler will create optimal code
(Well, I admit that doing this with
abs
is a bit artificial, but I hope you get the picture.)#define
是一个预处理器工具,具有宏语义。 宏考虑一下,如果
max(a,b)
是定义为#define max(a,b) ((a)>(b)?(a):(b) 的 )
:例 1:
val = max(100, GetBloodSample(BS_LDL))
会造成额外的无辜者流血,因为该函数实际上会被调用两次。这可能意味着实际应用程序的性能存在显着差异。示例 2:
val = max(3, schroedingerCat.GetNumPaws())
这表明程序逻辑存在严重差异,因为这可能会意外返回小于 3 的数字 - 这是用户意想不到的。
示例 3:
val = max(x, y++)
可能会将y
增加多次。使用内联函数,这些都不会发生。
主要原因是宏概念的目标是实现的透明性(文本代码替换),而内联的目标是正确的语言概念,使调用语义对用户更加透明。
#define
is a preprocessor tool and has macro semantics. Consider this, ifmax(a,b)
is a macro defined as#define max(a,b) ((a)>(b)?(a):(b))
:Ex 1:
val = max(100, GetBloodSample(BS_LDL))
would spill extra innocent blood, because the function will actually be called twice. This might mean significant performance difference for real applications.Ex 2:
val = max(3, schroedingerCat.GetNumPaws())
This demonstrates a serious difference in program logic, because this can unexpectedly return a number which is less than 3 - something the user would not expect.
Ex 3:
val = max(x, y++)
might incrementy
more than one time.With inline functions, none of these will happen.
The main reason is that macro concept targets transparency of implementation (textual code replace) and inline targets proper language concepts, making the invocation semantics more transparent to the user.