【问题标题】:Is it okay to have a method declared an inline method if its has a for loop in C++如果一个方法在 C++ 中有一个 for 循环,是否可以将一个方法声明为内联方法
【发布时间】:2009-10-23 17:46:47
【问题描述】:

我有一种如下所示的方法。 for 循环是否总是让编译器执行“内联请求”?

inline void getImsiGsmMapFrmImsi
  (
    const string& imsiForUEDir, 
    struct ImsiGsmMap& imsiGsmMap
  )
{
    for (int i = 0 ; (unsigned)i < imsiForUEDir.length() - 1 ; i++)
    {
         imsiGsmMap.value[i] = imsiForUEDir[i] - '0' ;
    }
    imsiGsmMap.length = imsiForUEDir.length() - 1 ;
}

【问题讨论】:

  • 哇。对不起,AraK 和史蒂文。 SO 团队真的需要处理多次编辑问题。
  • 谁必须阅读该代码,我深表同情。
  • 如果这是 C++,为什么要在结构名称前加上 struct?在 C++ 中,它们是一等公民,而不仅仅是标签。如果 i 需要是 unsigned (数组索引也需要),那你为什么要让它签名呢?您确定不想访问imsiForUEDir 中的最后一个元素吗? (对于有上下文的人,很明显这不是一个错误,而是故意的,但据我所见,它看起来很可疑。)
  • struct 未在原始方法中使用。它只是为了澄清这里的上下文。 (无符号)我是个问题。同意它不存在。是的,imsiForUEDir 的最后一个元素不应该被访问。
  • 唷,我很高兴他们在函数名称中将 From 缩写为 Frm。否则,该标识符将是无法忍受的

标签: c++ optimization loops inline


【解决方案1】:

您可以指定“内联”,如果感觉这样,编译器可以忽略它。

【讨论】:

    【解决方案2】:

    简单地说,不。

    inline”只是对编译器的提示。

    有一些方法可以强制编译器使用inline 某些东西,但这些方法是特定于编译器的。你的代码在我看来是移动的,所以这里有一些在各种手机平台上使用的 C++ 编译器的方法:

    Windows CE/Windows Mobile VC++ ARM 编译器使用 __forceinline 关键字代替提示“inline”。

    适用于 Windows CE/Windows Mobile 的更好的编译器(即更快的输出)是 cegcc,它使用最新的 GCC 4.4。在 GCC 中,__attribute__((always_inline))函数名之后和函数体之前写。

    更重要的是,内联这个循环是否是个好主意。我以编写手机为生,他们一般没有太多的CPU预算。但如果这个循环是一个瓶颈,我会感到非常惊讶。去掉你的程序所有的“内联”装饰,当你快要发货时,如果程序很慢,请分析它!

    一些编译器允许“配置文件引导优化”,他们可以制作出您以实际方式运行的检测二进制文件,然后他们使用如此收集的数据制作生产二进制文件,在那里他们就代码速度与代码大小做出明智的决定在您程序的各个部分中,以实现两者的最佳组合。

    【讨论】:

    • 没有?我会将答案解释为“是”。你可以在任何你想要的地方say 内联。编译器有权忽略你。 :-)
    • 他对“for 循环是否总是让编译器执行“内联请求”?”的回答是“否”
    • 请注意,即使使用__forceinline,编译器仍然可以忽略“请求”:“无法保证函数将被内联。您不能强制编译器内联特定函数,即使使用__forceinline 关键字”(msdn.microsoft.com/en-us/library/z8y1yy88.aspx)。我想 GCC 的 `always_inline 也是如此(文档似乎暗示该属性所做的唯一事情就是在优化关闭时导致内联发生)。在某个时刻,编译器会说“不!”。内联任何给定的递归函数将是一个非常巧妙的技巧。
    【解决方案3】:

    “没有循环函数的内联”可能是来自某些特定编译器的一些内联启发式方法。它并不普遍适用。

    每个编译器都使用一些启发式方法来确定函数是否应该内联,但通常每个编译器都使用自己的。所以,说循环会对内联产生一些普遍的影响是不正确的。它不会。您的函数中绝对没有任何东西可以从根本上排除内联。大多数现代编译器可以轻松内联这个函数,如果他们认为这是合理的,或者如果你强迫他们这样做。

    是的,一些编译器提供了非标准的声明说明符(或编译器选项),它们实际上会强制内联,即覆盖启发式分析,但内联确实超出的一些情况除外编译器的能力。例如,许多现代 C/C++ 编译器通常不能内联具有可变参数数量的函数(可变参数函数)。

    人们也普遍认为递归函数不能内联。实际上,在许多编译器中,递归函数可以内联到某个固定的递归深度,从而“压缩”递归。

    【讨论】:

      【解决方案4】:

      我想知道 inline 关键字是否还有必要。无论如何,现代编译器不大多只是忽略它并做他们认为最好的事情吗?

      【讨论】:

      • 在多个翻译单元中包含带有函数实现的header是必须的。
      • 一些编译器的设置迫使他们将inline 视为严格的顺序,而不是提示。一些编译器提供替代的非标准形式的 inline 关键字强制内联。
      • 如果我在类(即.h文件)中将方法声明为 void getImsiGsmMapFrmImsi(const string& imsiForUEDir,struct ImsiGsmMap& imsiGsmMap) 然后将方法定义为 inline void getImsiGsmMapFrmImsi(const string& imsiForUEDir) 是否正确,struct ImsiGsmMap& imsiGsmMap) {... } 在包含类 (.h) 文件的代码文件中?
      • 不,不是。 C++ 语言要求在使用它的所有翻译单元中定义(并且定义相同)。如果您希望在多个翻译单元中使用此函数,并希望将其设为inline,则最好将定义移至头文件。
      【解决方案5】:

      很可能编译器不会用循环内联函数,因为这有什么意义呢?如果代码是循环的,与循环相比,函数调用的成本通常是无法衡量的噪音。

      但是如果编译器想要内联它(也许编译器足够复杂,可以确定循环边界,甚至可以展开循环),它当然是允许的。

      但我不会打赌。

      【讨论】:

        【解决方案6】:

        总结我之前给这个的answer,在选择内联函数时应该注意的事项是:

        * local static variables
        * loop constructs
        * switch statements
        * try/catch
        * goto
        * recursion
        * and of course too much complexity (whatever that means)
        

        话虽如此,正如这里的其他答案所指出的那样,编译器是否内联函数基本上是未指定的。 7.1.2/2 有:

        带有 inline 说明符的函数声明(8.3.5、9.3、11.4)声明了一个内联函数。 inline 说明符向实现表明,在调用点对函数体进行内联替换优于通常的函数调用机制。在调用点执行此内联替换不需要实现;但是,即使省略了这个内联替换,7.1.2 中定义的内联函数的其他规则仍应遵守。

        一个有趣的细节是,编译器通常会标记这里涉及的行为类型。例如:“未指定”或“行为未定义”等。

        【讨论】:

          猜你喜欢
          • 2012-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-13
          • 2018-04-22
          • 2011-11-27
          • 2019-02-15
          • 2020-02-03
          相关资源
          最近更新 更多