Inline functions and scope

1
2
3
4
5
6
7
8
9
10
11
12
13
inline void foo(){
   int x;
   x = 10;
}

int main()
{
   int x;
   foo();
   x = 12;

   return 0;
}


Let's say the compiler does inline this. If inlining is just inserting the function into the calling function, how does it know the difference between x's here at run-time? This is probably some trivial nonsense I just brought up, but for some reason this thought came into my head.
If inlining is just inserting the function into the calling function

It's not. Whether a function is inlined or not has no effect on semantics.
It's not.


What do you mean? I thought that's exactly what happened (assuming compiler agrees). http://en.wikipedia.org/wiki/Inline_function
The semantics of the call will be preserved whether the function is inlined or not. Otherwise the program would behave differently depending on whether the function was inlined or not, and return statements would not behave properly at all.

If you like, you can think of copying the body of the function but including a set of { } around it to give its own scope, but even that doesn't fix the problem with copying in a return statement.
Inline expansion does not equal pure text replacement (as opposed to macros). Scoping rules are still respected.
The C standard expresses this somewhat more clearly than the C++ standard:

A function declared with an inline function specifier is an inline function. The
function specifier may appear more than once; the behavior is the same as if it appeared
only once. Making a function an inline function suggests that calls to the function be as
fast as possible.118) The extent to which such suggestions are effective is
implementation-defined.119)

118) By using, for example, an alternative to the usual function call mechanism, such as ‘‘inline
substitution’’. Inline substitution is not textual substitution, nor does it create a new function.
Therefore, for example, the expansion of a macro used within the body of the function uses the
definition it had at the point the function body appears, and not where the function is called; and
identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a
single address, regardless of the number of inline definitions that occur in addition to the external
definition.
That it would be clear the body of main can be rewritten the following way

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
   int x;

   {   // This is foo();
      int x;
      x = 10;
   }

   x = 12;

   return 0;
}


Take into account the additional braces that create a new scope for local variables.
Last edited on
Then I guess I'm just not sure how the inline actually works in the background. As Zhuge has stated, it obviously isn't just sticking the body of the function where the call was with {} around it. But as the standard says here it isn't a substitution either. If it isn't either of those, then what does it do if it also doesn't "call" the function?

EDIT:
@ Vlad,

But then foo()'s x is in the scope of main()'s x, right?
Last edited on
It injects the code at the calling site while preserving semantics so that the observable result is exactly the same as if the function had really been called (on the machine level, that is). How it does that is really up to the compiler.

But then foo()'s x is in the scope of main()'s x, right?

Not sure what you mean - the inner assignment refers to the inner x and the outer assignment refers to the outer x, so this works for this simple example.
Last edited on
No, the x on line 6/7 are different from the x on 3/10.

The standard simply says the inline keyword suggests to the compiler to make the call as fast as possible. Everything else is implementation-defined; this means the inline method (or if one is done at all!) is completely up to the compiler.

So really, asking "what does it do" is not really an answerable question. We could give some examples of how a particular function might ("might") be inlined (as vlad did for foo()) but to give a general algorithm would require looking at specific implementations.
Not sure what you mean - the inner assignment refers to the inner x and the outer assignment refers to the outer x, so this works for this simple example.


Then maybe I've had my definition of scope wrong this entire time (granted this particular type of issue has never came up) but the inner scope is also in scope of the main function, right? This would mean the inner scope is in the same scope as the outter x, so how would it know which x it's referring to? I'd imagine this results in a compiler error, but with inlining I'm not sure how it would react, and it's kind of impossible to test.

I also wasn't aware that inline is implementation defined when creating this thread. I assumed it was a straight substitution with some black magic dealing with return value.
I doubt there is a compiler today that pays any attention to the keyword inline when making decisions about inlining. The keyword specifies that multiple definitions are allowed and that function local statics , string literals, and closures are shared among all definitions, which involves black magic at linker level. Inlining is just normal optimization, like dead code elimination.
Last edited on
Topic archived. No new replies allowed.