tags:

views:

234

answers:

6

I have question when I compile an inline function in C++.

Can a recursive function work with inline. If yes then please describe how.

I am sure about loop can't work with it but I have read somewhere recursive would work, If we pass constant values.

My friend send me some inline recursive function as constant parameter and told me that would be work but that not work on my laptop, no error at compile time but at run time display nothing and I have to terminate it by force break.

inline f(int n) {
    if(n<=1)
        return 1;
    else {
        n=n*f(n-1);
        return n;
    }
}

how does this work?

I am using turbo 3.2


Also, if an inline function code is too large then, can the compiler change it automatically in normal function?

thanks

+3  A: 

I suppose your friend was trying to say that if given a constant, the compiler could calculate the result entirely at compile time and just inline the answer at the call site. c++0x actually has a mechanism for this called constexpr, but there are limits to how complex the code is allowed to be. But even with the current version of c++, it is possible. It depends entirely on the compiler.

This function may be a good candidate given that it clearly only references the parameter to calculate the result. Some compilers even have non-portable attributes to help the compiler decide this. For example, gcc has pure and const attributes (listed on that page I just linked) that inform the compiler that this code only operates on the parameters and has no side effects, making it more likely to be calculated at compile time.

Even without this, it will still compile! The reason why is that the compiler is allowed to not inline a function if it decides. Think of the inline keyword more of a suggestion than an instruction.

Assuming that the compiler doesn't calculate the whole thing at compile time, inlining is not completely possible without other optimizations applied (see EDIT below) since it must have an actual function to call. However, it may get partially inlined. In that case the compiler will inline the initial call, but also emit a regular version of the function which will get called during recursion.

As for your second question, yes, size is one of the factors that compilers use to decide if it is appropriate to inline something.

If running this code on your laptop takes a very long time, then it is possible that you just gave it very large values and it is simply taking a long time to calculate the answer... The code look ok, but keep in mind that values above 13! are going to overflow a 32-bit int. What value did you attempt to pass?

The only way to know what actually happens is to compile it an look at the assembly generated.

PS: you may want to look into a more modern compiler if you are concerned with optimizations. For windows there is MingW and free versions of Visual C++. For *NIX there is of course g++.

EDIT: There is also a thing called Tail Recursion Optimization which allows compilers to convert certain types of recursive algorithms to iterative, making them better candidates for inlining. (In addition to making them more stack space efficient).

Evan Teran
At first thank you but your answer is ambiguous for me. I m not clearly understand about inline what you write it.
R.K.Rahu
@R.K.Rahu: OK to clear it up. **a)** yes it can be done if the parameter is a constant, but not all compilers will do it. Some compilers give your the ability to help it make this decision. **b)** there is a thing called tail recursion which can be turned into a loop making inlining more likely. **c)** the inline keyword is a suggestion, not a command so the compiler is free to ignore it.
Evan Teran
thank you very much you take care of my comment and give clear suggestion your first answer also good but some.. but now I m clear and I have to work on it.
R.K.Rahu
A: 

You can inline recursive functions. The compiler normally unrolls them to a certain depth- in VS you can even have a pragma for this, and the compiler can also do partial inlining. It essentially converts it into loops. Also, as @Evan Teran said, the compiler is not forced to inline a function that you suggest at all. It might totally ignore you and that's perfectly valid.

The problem with the code is not in that inline function. The constantness or not of the argument is pretty irrelevant, I'm sure.

Also, seriously, get a new compiler. There's modern free compilers for whatever OS your laptop runs.

DeadMG
+4  A: 

This particular function definitely can be inlined. That is because the compiler can figure out that this particular form of recursion (tail-recursion) can be trivially turned into a normal loop. And with a normal loop it has no problem inlining it at all.

Not only can the compiler inline it, it can even calculate the result for a compile-time constant without generating any code for the function.

With GCC 4.4

int fac = f(10); 

produced this instruction:

movl    $3628800, 4(%esp)

You can easily verify when checking assembly output, that the function is indeed inlined for input that is not known at compile-time.

UncleBens
A: 

One thing to keep in mind - according to the standard, inline is a suggestion, not an absolute guarantee. In the case of a recursive function, the compiler would not always be able to compute the recursion limit - modern compilers are getting extremely smart, a previous response shows the compiler evaluating a constant inline and simply generating the result, but consider

bigint fac = factorialOf(userInput)

there's no way the compiler can figure that one out........

As a side note, most compilers tend to ignore inlines in debug builds unless specifically instructed not to do so - makes debugging easier

Tail recursions can be converted to loops as long as the compiler can satisfactorily rearrange the internal representation to get the recursion conditional test at the end. In this case it can do the code generation to re-express the recursive function as a simple loop

As far as issues like tail recursion rewrites, partial expansions of recursive functions, etc, these are usually controlled by the optimization switches - all modern compilers are capable of pretty signficant optimization, but sometimes things do go wrong.

Mark Mullin
+1  A: 

Recursive function can be inlined to certain limited depth of recursion. Some compilers have an option that lets you to specify how deep you want to go when inlining recursive functions. Basically, the compiler "flattens" several nested levels of recursion. If the execution reaches the end of "flattened" code, the code calls itself in usual recursive fashion and so on. Of course, if the depth of recursion is a run-time value, the compiler has to check the corresponding condition every time before executing each original recursive step inside the "flattened" code. In other words, there's nothing too unusual about inlining a recursive function. It is like unrolling a loop. There's no requirement for the parameters to be constant.

What you mean by "I am sure about loop can't work" is not clear. It doesn't seem to make much sense. Functions with a loop can be easily inlined and there's nothing strange about it.

What are you trying to say about your example that "displays nothing" is not clear either. There is nothing in the code that would "display" anything. No wonder it "displays nothing". On top of that, you posted invalid code. C++ language does not allow function declarations without an explicit return type.

As for your last question, yes, the compiler is completely free to implement an inline function as "normal" function. It has nothing to do with function being "too large" though. It has everything to do with more-or-less complex heuristic criteria used by that specific compiler to make the decision about inlining a function. It can take the size into account. It can take other things into account.

AndreyT
sorry I was wrong at some places. I write those line (i.e. loop ...) because in turbo 3.2 it creates problem.and one thing you said that I have to declare explicitly return type, I think you missed here, I think if we not mention any type that means, It is by default int.and I have also checked it again and it worked.
R.K.Rahu
@R.K.Rahu: No, I haven't "missed" here. Your post is tagged [C++]. In C++ language the return type of the function *must be explicitly declared*. No exceptions. There's no such thing as "it is by default int" in C++.
AndreyT
sorry Andrey, I have checked again because of you. But I got same.If we not declare return type then It will automatically it define "int" type. I have checked it on 5.02 turbo version so you missed here.
R.K.Rahu
@R.K.Rahu: No, again, I haven't missed. The result of your experiments simply mean that your compiler is broken. One more time: there's no "implicit int" rule in C++ language. It only existed in C. If your compiler allows an "implicit int" in C++ code, it is a problem with your compiler. The others have already noted that the compiler you are trying to use is old and outdated.
AndreyT
@R.K.Rahu: In the future, whenever you want to test a formal validity of C++ (or C) code, you can use this well-respected and very pedantic online compiler: http://comeaucomputing.com/tryitout . The results you get from your archaic Turbo C compiler are totally meaningless.
AndreyT
A: 

Hi,

Remember that the inline key word merely sends a request, not a command to the compiler. The compliler may ignore yhis request if the function definition is too long or too complicated and compile the function as normal function.

in some of the cases where inline functions may not work are

  1. For functions returning values, if a loop, a switch or a goto exists.
  2. For functions not returning values, if a return statement exists.
  3. If function contains static variables.
  4. If in line functions are recursive.

hence in C++ inline recursive functions may not work.

ksrao