0

I am currently learning C with the "Programming in C" by Stephen G. Kochan (3rd edition). In the chapter on recursive functions the factorial-function is presented. The part with recursion is result = n * factorial(n - 1); where n is the formal parameter of the number whose factorial is to be calculated and factorial is the function. Out of curiosity I changed the function call to factorial(--n) and while my Linter gives me a warning saying this operation on n may be undefined this compiles and runs as expected (I use gcc on Ubuntu). I cannot grasp what is happening here. In my understanding I should end up with a product of 0 (0 * 0 * 0 * ... * 1) with the last value being a one. But still this function returns the right values as with factorial(n - 1).

Here is the complete code of the function:

unsigned long int factorial(unsigned int n)
{
    unsigned long int result;

    if (n == 0)
        result = 1;
    else
        result = n * factorial(--n);

    return result;
}

To clarify: my question does not concern the undefined behaviour (why is this undefined behavior?), but how exactly this particular case is handled by the compiler. As this question was marked a duplicate, the answer to which does not apply here (although @badp answers my question in the duplicate but it is not the accepted answer there), I will answer it here.

Answer

@StoryTeller supplied an example, where this way of writing the function (n * factorial(--n) could lead to a behavior that is different from the one expected. @Pedram Azad gave an example of how one could find out how the compiler handles this by inspecting the assembly listing. The file containing this code can be generated by running gcc prog.c -S -o prog.s where prog.c is the file containing the c-code and prog.s is the file containing assembly-code. The important part is the -S option.

jruota
  • 147
  • 2
  • 8
  • Pretty much this http://c-faq.com/ansi/experiment.html – StoryTeller - Unslander Monica Dec 05 '17 at 13:40
  • I understand that this is undefined and therefore should not be assumed to work always as expected. My question aims more at how the compiler handles this case. – jruota Dec 05 '17 at 13:43
  • 1
    [Well, here's Microsoft's take on it](http://rextester.com/edit/ZOELF52488). What do you reckon they evaluated first? – StoryTeller - Unslander Monica Dec 05 '17 at 13:44
  • I believe this is unspecified, not undefined, behaviour. Either way, certainly shouldn't rely on any particular behaviour. – Oliver Charlesworth Dec 05 '17 at 13:45
  • 4
    The decrement is fine for `factorial(--n)`, but the behavior of `n *` is undefined. If you want to know what your compiler did, take a look at the assembly listing. In any case - besides curiosity - it just doesn't make sense to use the decrement operator, because there is no need to alter n. – Pedro Dec 05 '17 at 13:53
  • 1
    Since `n` isn't used afterwards, there isn't really any point doing `--n` - why not just do `n-1` and avoid any issues? – Chris Turner Dec 05 '17 at 13:57
  • 2
    `n` _is_ used afterwards. Maybe. The use of `n` in the expression `n * factorial(--n)` is not sequenced - this line of code invokes undefined behavior. It is a bug, anything can happen, hence the warning from Lint. – Lundin Dec 05 '17 at 14:07
  • If it works, you are lucky, because your compiler decided to perform the decrement on a copy in a separate register. That's all. I think that's what you wanted to know? – Pedro Dec 05 '17 at 14:09
  • @Pedram, if it appears to work, then you're **unlucky**, because you've missed the opportunity to fix the bug right now while you understand it! – Toby Speight Dec 05 '17 at 14:57
  • @TobySpeight I think this is rather a matter of understanding language - or a joke. ;-) – Pedro Dec 05 '17 at 15:16

0 Answers0