C++ inline functions and redeclarations

五迷三道 提交于 2019-12-11 19:47:59

问题


First of all, sorry for my English.

Since GCC totally ignores inline specifiers, it's a little difficult for me to know when a funcion has been marked inline by me or not. What I'm trying to understand is, when you have some redeclarations of a same function (in a same translation unit or in different ones), when or under which circunstances your function is marked inline or not (irrespective of what will the compiler make with your hint).

For example:

inline void print();

void print();

or:

void print();
inline print();

What is the meaning of redeclaring a function with different inline specifiers? A more complex example:

#include <iostream>

void print();

int main()
{
    print(); // (1)
}

inline void print() { std::cout << "HELLO" << std::endl; }

From the exclusive point of view of C++ and not from the point of view of a compiler, is the print function an inline one at line (1)?

I cannot formulate my question conciselly, but I think the message has been received :) I'm trying to understand when a function is supposed to be marked inline and when not from the point of view of C++ and the programmer's (irrespective of what will the compiler make with your function).


回答1:


This sentence:

Since GCC totally ignores inline specifiers, it's a little difficult for me to know when a function has been marked inline by me or not.

is an incorrect basis to start with. (And of course, we can replace GCC with any other modern compiler for this discussion).

Sure, the compiler may ignore the inline keyword for the purposes of deciding whether the function is inlined or not - and it CERTAINLY can inline functions that are NOT marked inline. The compiler does, however, use the inline keyword [and it's equivalence of "body declared inside the struct"] when generating the final output, to avoid multiple definitions of a function that has code generated multiple times in different compile units. For example:

 foo.h:
    inline int foo() { return 42; }

 a.cpp:
    #include "foo.h"

    ...

 b.cpp:
    #include "foo.h"

    ... 

If the function foo was not declared inline, the linker would complain about multiple definitions of the function foo if we link the results of a.cpp and b.cpp into one executable file.

However, you are right in that the compiler will not decide to inline functions on the basis of the inline keyword, but based on other aspects, such as how many times the function is called, whether the source of the function is "visible" to the compiler, etc.

As a simple rule:

  1. Compiler will not inline functions that it hasn't got the source code for.
  2. Compiler will not inline virtual functions (unless it can determine the type of the object the virtual function belongs to)
  3. The compiler will inline functions that are small and/or only called once, particularly if the function is static.

Since inlining happens towards the end of compilation (when ALL the source code have been parsed and placed in some sort of AST (Abstract Syntax Tree) or similar form), whether the function is before or after the point of usage typically doesn't really matter - of course, if the call is to a function that isn't part of the AST (the source code is not available), the compiler has no choice but to NOT inline it.

The exception to "can't inline when the source isn't available" is so called LTO "Link Time Optimisation". A traditional linker will just take a collection of machine code instructions and paste them together in whatever order they are listed, without any knowledge of what a function is [simplified view, sufficient for this discussion] and then fix up any addresses for functions and variable that the compiler couldn't resolve directly. In contrast, LTO stores the "object files" as an intermediate representation, and the final machine code generation is done by the linker phase. This means that the linker has enough information to for example move code around to inline the code in one function into another. This technology is available in recent releases of for example gcc (4.9.0 has LTO as a full feature, earlier versions had a bit less support)




回答2:


inline allows an external linkage function to be defined (essentially identically) in two or more translation units.

which means defining it in a header.

when a function is inline it must be defined, and inline, and essentially 1)identically, in every translation unit where it's used.


inline just accumulates. a function can't become un-inline.


in addition to these considerations inline serves as an optimization hint, that the compiler may freely ignore. in that capacity it states that you would like the machine code calls to this function to be inlined. generally the compiler can do a better job of deciding where that's a good idea or not.


1 C++17 10.1.6/5 (dcl.inline/5): “An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case”



来源:https://stackoverflow.com/questions/23595664/c-inline-functions-and-redeclarations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!