内联这个函数还是不内联?
我应该实现一个函数来比较两个类似的字符串,所以 strcmp
但忽略空白字符,所以
strcmpignorews("abc ", " a b c")
应该给出相同的结果。
这是我的实现:
namespace {
void SkipWhitespace(const char *&s) {
for (; std::isspace(*s, std::locale::classic); ++s);
}
}
int strcmpignorews(const char *s1, const char *s2) {
for (; *s1 != '\0' && *s2 != '\0'; ++s1, ++s2) {
SkipWhitespace(s1);
SkipWhitespace(s2);
if (*s1 != *s2) {
break;
}
}
return (*s1 < *s2) ? -1 : ((*s1 == *s2) ? 0 : 1);
}
现在的问题是,内联 SkipWhitespace 函数是否有意义?我想我在某处读到过 inline
不应该用于包含循环或开关的函数,但我不记得在哪里以及为什么。
I'm supposed to implement a function which compares two strings simliar so strcmp
but ignoring whitespace characters, so
strcmpignorews("abc ", " a b c")
should give the same result.
Here's my implementation:
namespace {
void SkipWhitespace(const char *&s) {
for (; std::isspace(*s, std::locale::classic); ++s);
}
}
int strcmpignorews(const char *s1, const char *s2) {
for (; *s1 != '\0' && *s2 != '\0'; ++s1, ++s2) {
SkipWhitespace(s1);
SkipWhitespace(s2);
if (*s1 != *s2) {
break;
}
}
return (*s1 < *s2) ? -1 : ((*s1 == *s2) ? 0 : 1);
}
Now, the question is, would it make sense to inline the SkipWhitespace function? I think I've read somewhere that inline
should not be used for functions which contain loops or switches but I can't remember where and why.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
从历史上看,内联一直向编译器表明它应该将函数体插入到调用站点中。然而,这不再是一个有意义的注释。无论是否存在内联限定,现代编译器都会内联函数。
需要强调的是,编译器是否会执行内联优化完全不由您掌控。
在现代使用中,内联只有一种功能。它可用于使链接器忽略多个符号,就像在多个编译单元中定义函数时一样。该技术可用于打破循环依赖。将内联用于没有其他目的。
Historically, Inline has been an indication to the compiler that it should insert the function body into the call site. However, that is no longer a meaningful annotation. Modern compilers will inline a function or not regardless of the presence or absence of
inline
qualification.To emphasize, whether compiler will perform inline optimization is completely out of your hands.
In modern use, inline has only one function. It can be used to get the linker to ignore multiple symbols, as when a function is defined in multiple compilation units. This technique can be used to break circular dependencies. Use inline for no other purpose.
我不会说在这种情况下不应该使用它,但如果代码相对较快,内联代码的行为将会有更大的好处。
这是因为内联消除了函数调用的开销。如果函数调用和返回需要一秒钟,但您内联的代码需要十分钟,那么您不会看到巨大的改进。但是,如果您内联的代码也需要一秒钟,那么其性能基本上会提高一倍。
请记住,
inline
是对编译器的一种建议,如果编译器发现您错了,或者即使它只是令人讨厌,它可以自由地忽略它。我很少使用它,也很少发现需要它,将它归为与auto
和register
相同的类别(至少在 C 中)。I wouldn't say it shouldn't be used under those circumstances but the act of inlining code will have a larger benefit if the code is relatively quick.
That's because inlining gets rid of the overhead of a function call. If a function call and return takes one second but the code you're inlining takes ten minutes, you're not going to see a huge improvement. But, if the code you're inlining also takes one second, you'll basically double its performance.
Just keep in mind that
inline
is a suggestion to the compiler, one it can freely ignore if it figures out you're wrong or even if it's just being obnoxious. I rarely use it and rarely find a need for it, relegating it to the same category asauto
andregister
(at least in C).inline
关键字一直只是对编译器的一个建议。这意味着如果编译器如此选择,那么它可能会忽略该建议。最重要的是,如果编译器可以内联函数,即使您没有要求它这样做,它也可能会内联该函数。也就是说,为了让编译器内联函数,它必须知道函数的主体。如果函数是在单独的编译单元中定义的,则编译器可能不知道该编译单元之外的函数定义。在这种情况下,编译器只能在定义该函数的编译单元内的调用者中内联该函数。因此,要从中得出的一点是,如果您希望允许编译器内联函数,那么您必须在类定义中定义该函数或添加
inline
关键字并在标题中定义它。内联函数不违反 ODR。您应该考虑的另一个考虑因素是,由于内联函数必须驻留在标头中,并且由于标头通常由许多编译单元包含,因此内联函数会增加静态耦合。这意味着更改内联函数的定义将导致所有依赖编译单元的级联编译。这很重要:函数的定义不应该是接口的一部分,但内联函数强制这种耦合。
仅就最后一点而言,最后我会说永远不要内联函数。也就是说,直到您对应用程序或库的运行时性能感到恼火为止,此时您应该运行分析器以查看是否有任何特定函数可以提高内联性能。如果内联函数产生的目标代码比生成函数调用所需的代码更小,那么内联函数还可以减小可执行文件的大小,但这在大多数(但很少)(嵌入式?)上下文中并不是一个重要的决策因素。
探查器可以告诉您特定的函数如果内联,可以提高性能,但它不能告诉您特定的内联函数如果未内联,是否可以提高性能(大小、运行时、开发......)。
The
inline
keyword has always been a mere suggestion for the compiler. That means that if the compiler so chooses then it may ignore the suggestion. On top of that, if the compiler can inline a function it may inline the function even if you didn't ask it to do so.That said, in order for the compiler to inline a function it must know the function's body. If the function is defined in a separate compilation unit then the compiler probably doesn't know the function's definition outside that compilation unit. In this case the compiler can only inline the function in callers within the compilation unit that defines the function. So the point to take from that is that if you want to allow the compiler to inline a function then you must define the function in the class definition or add the
inline
keyword and define it in the header. Inline functions don't violate the ODR.Another consideration you should make is that because inline functions must reside in a header, and because headers are typically included by a number of compilation units, inline functions increase static coupling. That means that changing the definition of an inline function will cause a cascade in compilation through all dependent compilation units. This is important: a function's definition is not supposed to be part of the interface, but inline functions force this coupling.
For that last point alone, at the end, I'd say never inline a function. That is, until you are irritated enough by the runtime performance of your application or library, at which point you should run your profiler to see if any particular functions would boost performance inlined. Inline functions can also reduce the executable's size if inlining them results in a smaller object code than code necessary for generating a function call, but that's less a significant decision factor in most but few (embedded?) contexts.
The profiler can tell you that a particular function can boost performance if it's inlined, but it can't tell you if a particular inlined function can boost performance (size, runtime, development, ...) if it's un-inlined.
一般来说,内联之前分析。
内联始终是对编译器的建议。它保留忽略您或同意您的权利。无论如何,它可能会在未经您许可的情况下内联代码的其他部分。
如果您不介意额外输入,这里有一些将方法或函数声明为内联的指南:
大于或等于指令
调用、初始化的周期,
清理并从
方法。
到其他方法。
小环可以装入
处理器的缓存)。
是内联的或可以内联的,这
包括库函数。
(
#define
)。(5除外),并且彻底
已测试。 (你能说重建所有
依赖项,因为您更改了
header?)
我的风格是内联类 getters &设置器。任何易失性(不起作用或可能发生更改)或复杂的代码都不会被内联。
In general, Profile before inlining.
Inlining is always a suggestion to the compiler. It retains the right to ignore you or agree with you. It may be inlining other parts of your code without your permission anyway.
If you don't mind extra typing, here are some guidelines for declaring a method or function as inline:
than or equal to the instruction
cycles for calling, initializing,
cleaning up and returning from the
method.
to other methods.
small loops can fit into a
processor's cache).
are inlined or can be inlined, this
includes library functions.
(
#define
).(except 5), and is thoroughly
tested. (Can you say rebuild all
dependencies because you changed a
header?)
My style is to inline class getters & setters. Any code that is volatile (either not working or subject to change) or is complex will not be inlined.
在上下文中,使用
inline
没有任何坏处,而且可能还有一些好处。编译器将内联的函数的复杂性是有限制的;具有复杂循环或开关的函数比没有复杂循环或开关的函数更有可能达到该限制。所以,你读到的并不全是错的;它只需要合格即可。
从风格上来说,我会使用
while
循环代替for
循环:这也修复了代码中仅跳过非空白字符的错误。 (在输入此答案时错误已修复!)
In the context, there is no harm and possibly some good in using
inline
.There are limits on the complexity of a function that the compiler will inline; functions with complex loops or switches are more likely to reach that limit than functions without. So, what you read isn't all wrong; it just needs to be qualified.
Stylistically, I'd use a
while
loop in place of yourfor
loop:This also fixes the bug in your code which only skips characters that are not white space characters. (The bug was fixed while this answer was typed!)