我应该实现一个比较两个字符串simliar 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
不应该用于包含循环或开关的函数但是我不记得在哪里以及为什么。
答案 0 :(得分:14)
从历史上看,Inline已经向编译器表明它应该将函数体插入到调用站点中。但是,这不再是一个有意义的注释。无论是否存在inline
资格,现代编译器都会内联函数。
要强调的是,编译器是否会执行内联优化完全不在您的手中。
在现代使用中,内联只有一个功能。它可用于使链接器忽略多个符号,如在多个编译单元中定义函数时。此技术可用于打破循环依赖关系。使用内联无其他目的。
答案 1 :(得分:3)
我不会说不应该在这些情况下使用,但如果代码相对较快,内联代码的行为将会有更大的好处。
这是因为内联消除了函数调用的开销。如果一个函数调用和返回需要一秒钟,但你内联的代码需要十分钟,你将不会看到巨大的改进。但是,如果您内联的代码也需要一秒钟,那么您的性能基本上会翻倍。
请记住,inline
是编译器的建议,如果它发现你错了,或者即使它只是令人讨厌,它也可以自由忽略。我很少使用它,很少发现需要它,将它降级到与auto
和register
相同的类别(至少在C中)。
答案 2 :(得分:3)
inline
关键字一直只是编译器的建议。这意味着如果编译器如此选择,那么它可能会忽略该建议。最重要的是,如果编译器可以内联函数,即使你没有要求它,也可以内联函数。
也就是说,为了让编译器内联函数,它必须知道函数的主体。如果函数是在单独的编译单元中定义的,那么编译器可能不知道该编译单元之外的函数定义。在这种情况下,编译器只能在定义函数的编译单元内的调用者中内联函数。因此,需要注意的是,如果您希望允许编译器内联函数,那么您必须在类定义中定义函数或添加inline
关键字并在其中定义标题。内联函数不违反ODR。
您应该考虑的另一个因素是因为内联函数必须驻留在标题中,并且因为标题通常包含在许多编译单元中,所以内联函数会增加静态耦合。这意味着更改内联函数的定义将导致通过所有相关编译单元进行编译级联。这很重要:函数的定义不应该是接口的一部分,但是内联函数强制这种耦合。
仅针对最后一点,最后,我会说从不内联函数。也就是说,在您对应用程序或库的运行时性能感到烦恼之前,您应该运行探查器以查看是否有任何特定功能可以提高内联性能。内联函数也可以减少可执行文件的大小,如果内联它们导致比生成函数调用所需的代码更小的目标代码,但在大多数(嵌入式?)上下文中,这不是一个重要的决策因素。
分析器可以告诉你一个特定的函数如果内联它可以提高性能,但它不能告诉你一个特定的内联函数是否可以提高性能(大小,运行时,开发......),如果它没有内联
答案 3 :(得分:3)
一般来说,内联前的配置文件。
内联始终是编译器的建议。它保留拒绝您或同意您的权利。无论如何,它可能会在未经您许可的情况下内联您的代码的其他部分。
如果您不介意额外输入,可以使用以下方法将方法或函数声明为内联:
#define
)。我的风格是内联类getter&amp; setter方法。
。任何易变的代码(不工作或可能会发生变化)或复杂的代码都不会内联。答案 4 :(得分:2)
在上下文中,使用inline
没有任何伤害,可能也有一些好处。
编译器将内联的函数的复杂性有限制;具有复杂循环或开关的函数比没有函数的函数更有可能达到该限制。所以,你读到的并不是全错;它只需要合格。
在风格上,我使用while
循环代替for
循环:
while (isspace(*s, std::locale::classic))
++s;
这也修复了代码中的错误,该错误只会跳过不是空格字符的字符。 (在输入此答案时修复了错误!)