4

Consider the classic way of defining a factorial function:

#include <stdio.h>

__attribute__((always_inline)) inline int factorial(int n)
{
    if (n == 1){
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

int main()
{
    printf("value %d", factorial(7/*guaranteed to not overflow int*/));
}

I'm forcing my compiler (gcc) to inline the factorial function. That should cause a problem. gcc is ignoring my force inline without error. Is this expected?

P45 Imminent
  • 8,319
  • 4
  • 35
  • 78
  • 2
    recursive function can't be inline functions. I think the compiler is ignoring your "attribute" because of this – Astinog Sep 10 '15 at 09:42
  • 1
    @Agostino: If you read the question, the OP know it, that's why he asked this... – Melkon Sep 10 '15 at 09:47
  • Since you called factorial with a constant, how do you know it wasn't inlined? I don't know if gcc is that smart. When I tested icc many years (and versions ago) it wasn't that smart (such optimizations of constants occurred after, not intermixed with inlining). But maybe gcc now is smarter than icc then. – JSF Sep 10 '15 at 09:48
  • @Agostino Interesting, but I thought inline recursive functions could be changed into loops untill certain depths, effectively inlining the recursive function (http://stackoverflow.com/questions/190232/can-a-recursive-function-be-inline). – Floris Velleman Sep 10 '15 at 09:52
  • 1
    @FlorisVelleman wow, I didn't know that, thanks – Astinog Sep 10 '15 at 09:53
  • @FlorisVelleman Optimising the calls out of recursive functions is head- and tail-call optimisation, not inlining. Not sure if gcc is smart enough to work that out, but something like `int fact(int x, int y) { return x == 1 ? y : fact(x - 1, x * y); }` might work... This is irrelevant to `inline`. – autistic Sep 10 '15 at 10:49
  • @Seb There seems to be something going on in using the `inline` keyword for these examples though: http://goo.gl/5lFsfP (with), http://goo.gl/zye7Zt (without). It changes the output quite drastically (not using tail call elimination). – Floris Velleman Sep 10 '15 at 11:01
  • @FlorisVelleman What did you conclude regarding `static` versus `extern` (default)? Also, you got the arguments around the wrong way. – autistic Sep 10 '15 at 23:27
  • Have you tried using [constexpr like in this example](http://stackoverflow.com/a/26851456/1708801). If you arguments are constant expressions it should be able to perform the operation at compile time. – Shafik Yaghmour Sep 12 '15 at 17:17

1 Answers1

4

From GCC's documentation:

GCC does not inline any functions when not optimizing unless you specify the always_inline attribute for the function.

So always_inline doesn't mean "inline this or diagnose", it means "inline even if optimizations are off". It will still refuse to inline something if it's not possible or reasonable.

As you can see here, for an example as simple as yours the whole function can be optimised out and the result calculated at compile-time. Even if the argument is not a compile-time constant, the function can still be inlined. Recursion doesn't always make inlining impossible.

However, as pointed out by Floris Velleman, if you turn optimizations off it will fail to compile, stating that the function is not considered for inlining, even though it will inline it if optimizations are on. Seems like the actual handling of the attribute is not fully consistent with the documentation.

Community
  • 1
  • 1
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • 1
    Nice answer, interesting how this results in a compile-time error if you happen to compile it without optimizations, seems like `constexpr` is a better fit if you happen to work with compile-time constants. – Floris Velleman Sep 10 '15 at 09:57