Thread: Inline functions and passing by value

  1. #1
    Registered User
    Join Date
    Jun 2006
    Posts
    3

    Inline functions and passing by value

    As I have been taught it, the code of an inline function is expanded into its call during compilation. Thus, for example, given the definition

    Code:
    inline int max{
       return x > y ? x : y;
    }
    a line

    Code:
    int a = max(b,c);
    should expand into
    Code:
    int a = b > c ? b : c;
    But now say I have a program with an inline function like the following which is supposed to change one of its arguments:

    Code:
    #include<iostream>
    using namespace std;
    
    inline void set(int x, int y){
       x = y;
    }
    
    int main(){
       int a = 3, b = 5;
       cout << a << " " << b << endl;
       set(a,b); //I would think this is replaced by a = b;
       cout << a << " " << b << endl;
       return 0;
    }
    The output of this is the same for both lines: a = 3, and b = 5, and thus a is not changed to 5, as I would initially think would happen with an inline function. Of course, with a non-inline function, set(a,b) passes by value, so a and b should stay unchanged. (Oddly enough, I have successfully been able to change the variable a if I write set(a,b) as a parameterized macro.) But how do I resolve these two conflicting ideas I have, that (1) inline functions expand the function code whenever the function is called; (2) inline functions seem to pass by value, like regular functions?
    Last edited by gentinex; 06-05-2006 at 10:19 PM.

  2. #2
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    inline functions are a help to the compiler for optimizations, they do not change the semantics of functions. Arguments are still treated as if they're passed by value.

    It depends on the compiler, but perhaps it's expanded to:
    Code:
    int a = 3, b = 5;
    set(a, b);
    
    ==>
    
    int a = 3, b = 5;
    int x = b;
    
    or even (more poorly) ==>
    
    int a = 3, b = 5;
    int x = a;
    int y = b;
    x = y;
    (which might be optimized away totally as the values are never used and have no side-effects)
    Last edited by Magos; 06-05-2006 at 10:34 PM.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  3. #3
    Registered User
    Join Date
    Jun 2006
    Posts
    3
    If the compiler is going for optimization, then why wouldn't it just plug in "a = b;", instead of going through the work of initializing new variables x and y as in your example? Are compilers really so omniscient that in some cases (like the max() example above) they'll just copy and paste code, whereas in other cases (like the set() example above) they'll go through the trouble of initializing variables? How would a complier know when it's necessary to initialize new variables and when it's not necessary? Does it occur in the set() example because there's an lvalue involved, i.e. the assignment?

  4. #4
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Quote Originally Posted by gentinex
    why wouldn't it just plug in "a = b
    The set function sets the local variable x to b, NOT a. a is only used to "initialize" x. I think you mistake inline functions for macros which would expand it to a = b.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  5. #5
    Registered User
    Join Date
    Jun 2006
    Posts
    3
    I understand that in your example x is set to b. But my question was, "why would the compiler even bother to initialize new variables x and y in the first place, if it's looking to optimize?"

    To see this question from another perspective, take the inlint int max() example above. If a compiler encounters
    Code:
    c = max(a,b);
    will it
    (1) replace it with
    Code:
    c = a > b ? a : b;
    or (2) replace it with
    Code:
    int x = a;
    int y = b;
    c = x > y ? x : y;
    The books/websites I have been reading lead me to believe that compilers would replace it with (1), so that it doesn't have to add the extra work of initializing x and y which occurs in (2). If this is true for inline int max(), my question is why it isn't also true for set()? Is it because set() has an assignment to one of its arguments, i.e., an lvalue, and the compiler somehow "knows" that lvalues should be treated differently? Or is what I'm reading just wrong---inline functions avoid putting functions on the stack, but they still have to do the work of initializing copies of variable arguments?
    Last edited by gentinex; 06-06-2006 at 07:15 PM.

  6. #6
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    I did say "perhaps it is expanded to", as it's entirely up to the compiler how to implement it. I was just stating the keeping of semantics. If you're interested in exact implementation check out the resulting assembly, in MSVC I believe it's flag /FA.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Oddly enough, I have successfully been able to change the variable a if I write set(a,b) as a parameterized macro.
    ...
    The books/websites I have been reading lead me to believe that compilers would replace it with (1), so that it doesn't have to add the extra work of initializing x and y which occurs in (2). If this is true for inline int max(), my question is why it isn't also true for set()?
    The thing is, inline functions are not macros. They do not perform dumb text replacement, but rather follow the scope rules of C++. I guess that if the compiler is indeed able to just re-use the variables, it will do so, but never in a way that will change the semantics (i.e. meaning) of the function. Note that the compiler isnt even required to perform inline substitution of a function declared inline.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    Why do you think experienced C folks recommend inline functions over macros? Because they are type-and-scope-safe. They follow all the function conventions. Say you have a macro (classic example)

    Code:
    #define square(x) x*x
    What if you used it
    Code:
    foo = square(bar + baz);
    Even worse, this would pass the compile step:
    Code:
    foo = square("bar");
    But if you write it as an inline function
    Code:
    inline int square(int x)
    { return x * x; }
    An optimizing compiler might expand it to
    Code:
    foo = (bar + baz) * (bar + baz);
    Thus eliminating any overhead from function calls.
    Last edited by jafet; 06-07-2006 at 02:12 AM.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  9. #9
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by gentinex
    I understand that in your example x is set to b. But my question was, "why would the compiler even bother to initialize new variables x and y in the first place, if it's looking to optimize?"
    The inline specifier is not a request for the compiler to optimize the function code. It is important to understand this. It is simply a request for the compiler to expand the body of the function wherever it is called.

    When Magos talked about optimization, he was referring to the fact that this does effectively optimizes the code, since you remove the extra overhead of calling that function.

    But whatever extra optimization is taken place afterwards, or before that, to the function code, is not the direct result of using the inline specifier.

    There is another thing you must remember. It's said everywhere that inline is simply a request to the compiler. It may choose or not to replace the function call with an in-line expansion of the function body. Right. Fine... However, this also means that the same function may be expanded within one context, and not within another. That is, the same program may have places on the code where expansion took place, and others where the function was not expanded.

    With this in mind you will, I believe, understand better that optimization has nothing to do with the inline specifier. At least not directly.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems passing a file pointer to functions
    By smitchell in forum C Programming
    Replies: 4
    Last Post: 09-30-2008, 02:29 PM
  2. Replies: 2
    Last Post: 07-03-2008, 11:31 AM
  3. Replies: 7
    Last Post: 04-19-2006, 11:17 AM
  4. Passing pointers between functions
    By heygirls_uk in forum C Programming
    Replies: 5
    Last Post: 01-09-2004, 06:58 PM
  5. Passing data/pointers between functions #2
    By TankCDR in forum C Programming
    Replies: 1
    Last Post: 11-02-2001, 09:49 PM