0

I read from the following website, that the compiler may not perform inlining when the function has static variables. What is the reason?

Reference: Inline Functions in C++

Remember, inlining is only a request to the compiler, not a command. Compiler can ignore the request for inlining. Compiler may not perform inlining in such circumstances like:

  1. If a function contains a loop. (for, while, do-while)
  2. If a function contains static variables.
  3. If a function is recursive.
  4. If a function return type is other than void, and the return statement doesn’t exist in function body.
  5. If a function contains switch or goto statement.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Krishna Kanth Yenumula
  • 2,533
  • 2
  • 14
  • 26
  • 6
    That article is out of date. In modern C++, `inline` has nothing to do with optimization and instead affects the linkage of variables and functions. See https://en.cppreference.com/w/cpp/language/inline – alter_igel May 13 '20 at 04:55
  • 3
    The compiler inlines a function only when it wants to, and it typically wants to when the result is faster execution. Generally, you should not worry about what gets inlined until you detect a problem related to inlining. Still, it doesn't seem to me like such a question warrants a negative score. – JaMiT May 13 '20 at 04:59
  • The "inlined" static variable should still "refer" to the original inlined function (as that function might be called several times). That difficulty can be dropped by not inlining such function. – Jarod42 May 13 '20 at 08:10
  • This is being discussed on [meta](https://meta.stackoverflow.com/q/397429/3404097). – philipxy May 15 '20 at 01:12
  • This is a special case of a faq. Before considering posting please read your textbook and/or manual & google any error message or many clear, concise & precise phrasings of your question/problem/goal, with & without your particular strings/names & site:stackoverflow.com & tags; read many answers. If you post a question, use one phrasing as title. Reflect your research. See [ask] & the voting arrow mouseover texts. – philipxy May 15 '20 at 01:13
  • Does this answer your question? [When do compilers inline C++ code?](https://stackoverflow.com/questions/1443982/when-do-compilers-inline-c-code) – philipxy May 15 '20 at 01:20
  • @philipxy It does not answer my question. – Krishna Kanth Yenumula May 15 '20 at 03:26
  • 1
    Yes, it does. The compiler can choose to not inline for any reason at all & inline for any reason at all. Unfortunately, "may not perform" is ambiguous in English--it can have many meanings. For the quote to be correct, it must mean "might not perform" when ..., but it is also true that it might perform when .... You ought to clarify what *you* mean by "may not perform" & what you think the quote might mean by it, but the answers here & at the link & at many other links make clear that it might, and it might not, and it doesn't matter what the website is trying to say. – philipxy May 15 '20 at 03:38

3 Answers3

3

In general, the compiler will decide what to inline and not. The purpose of the inline keyword has changed to mean that something is allowed mutiple definitions.

Here's a quote from cppreference

The original intent of the inline keyword was to serve as an indicator to the optimizer that inline substitution of a function is preferred over function call, that is, instead of executing the function call CPU instruction to transfer control to the function body, a copy of the function body is executed without generating the call. This avoids overhead created by the function call (passing the arguments and retrieving the result) but it may result in a larger executable as the code for the function has to be repeated multiple times.

Since this meaning of the keyword inline is non-binding, compilers are free to use inline substitution for any function that's not marked inline, and are free to generate function calls to any function marked inline. Those optimization choices do not change the rules regarding multiple definitions and shared statics listed above.

Because the meaning of the keyword inline for functions came to mean "multiple definitions are permitted" rather than "inlining is preferred", that meaning was extended to variables.

Community
  • 1
  • 1
super
  • 12,335
  • 2
  • 19
  • 29
2

Compilers can totally inline functions with loops static variables, switch statements, and even recursive functions.

Here's an example:

#include <iostream>

inline int foo(int* a, int n)
{
    int r = 0;
    static int b;
    for (int i = 0; i < n; i++)
    {
        r += a[i];
    }
    switch (n)
    {
    case 42:
        std::cout << "???\n";
    }
    return r;
}

inline int foo2(int n)
{
    return n == 0 ? 0 : 1 + foo2(n - 1);
}

int main()
{
    int bar[3];
    for (int i = 0; i < 3; i++)
    {
        std::cin >> bar[i];
    }
    std::cout << foo(bar, 3) << '\n';
    std::cout << foo2(bar[0]) << '\n';
}

And here's the assembly code which the compiler generated:

main:
        sub     rsp, 24
        mov     edi, OFFSET FLAT:_ZSt3cin
        lea     rsi, [rsp+4]
        call    std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
        lea     rsi, [rsp+8]
        mov     edi, OFFSET FLAT:_ZSt3cin
        call    std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
        lea     rsi, [rsp+12]
        mov     edi, OFFSET FLAT:_ZSt3cin
        call    std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
        mov     esi, DWORD PTR [rsp+8]
        mov     edi, OFFSET FLAT:_ZSt4cout
        add     esi, DWORD PTR [rsp+4]
        add     esi, DWORD PTR [rsp+12]
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     edx, 1
        lea     rsi, [rsp+3]
        mov     BYTE PTR [rsp+3], 10
        mov     rdi, rax
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        mov     esi, DWORD PTR [rsp+4]
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        lea     rsi, [rsp+3]
        mov     edx, 1
        mov     BYTE PTR [rsp+3], 10
        mov     rdi, rax
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        xor     eax, eax
        add     rsp, 24
        ret
_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

Notice that in the assembly code, there is no call to foo or foo2in the main function. The addition of the array elements is performed by the instructions mov esi, DWORD PTR [rsp+8], add esi, DWORD PTR [rsp+4], and add esi, DWORD PTR [rsp+12] in the middle of the main function. The article is either wrong or it used "may not" to mean "might not" instead of "isn't allowed to". The latter case would make sense because the compiler is less likely to inline larger and more complex functions.

Also, as explained in the other answers, compilers can inline functions without the inline keyword. If you remove the inline keyword from the example above, the compiler will still inline the function.

eesiraed
  • 4,626
  • 4
  • 16
  • 34
  • 2
    Compilers certainly *can*, but they are not *required* to do so. That is the point of the quoted explanation. In fact, the explanation could go even further: `inline` *never* places any obligations on the compiler with regard to inline code generation. – Cody Gray - on strike May 14 '20 at 05:46
  • @CodyGray The OP seems to be under the impression that compilers are not allowed to inline functions with loops, switch statements, or recursion, so I demonstrated that this is not the case whether `inline` was used or not. I assumed the OP knows that compilers are not required to inline functions marked with `inline` since that was clearly stated in the linked article. – eesiraed May 14 '20 at 21:36
2

When the article says "may not perform", I think it means "might not perform" seeing how that phrase comes shortly after "can ignore". If that's the case, the compiler does not really need a reason for not inlining a function. The compiler inlines at its own discretion.

Still, there usually is a reason for what compilers do and don't do. Newer compilers are more adept at inlining functions than older ones. It's possible that the author of the article experimented with a compiler that simply lacked support for inline functions with static variables. I would expect that newer compilers do not have this limitation.

Keep in mind the age of information when evaluating the limitations of compilers. I don't see a date for that article. Its comments stretch back three years, though (and its information seems older than that). A lot can happen over three years. Compilers evolve and get better. What had been impossible may have become commonplace.

Not to mention that the major theme of that article is off-base. The inline keyword in C++ has had nothing to do with whether or not a function is inlined since at least C++98 (twenty-two years ago).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JaMiT
  • 14,422
  • 4
  • 15
  • 31