0

I came across this code somewhere when practicing basic C questions:

int func(num) {
    if (num > 0) {
        return (num + func(num - 2));
    }
}

int main() {
    printf("%d\n", func(5));
    return 0;
}

The code when executed returns 8 as the answer. But I think that the answer should be "cannot be determined".

The recursive calls in my head looks like this:

5 + func(3)  => 5 + (3 + func(1))
3 + func(1)  => 3 + (1 + func(-1))
1 + func(-1) => 1 + (?)

For the ? symbol, I think reading the return value for func(-1) is undefined behavior. I'm basing this on the assumption that for func(-1) no explicit int value is being returned. So reading from func(-1) in the expression (1 + func(-1)) should produce some garbage result + 1 in my opinion.

Why is that the code is returning 8 as the answer and not something garbage?

When I explicitly pass a negative number to func and read the result I do get the garbage value, such as in this code;

int main() {
    printf("%d\n", (1 + func(-1)));   // returns garbage result and not 0
    return 0;
}

Why is that in the recursive call (1 + func(-1)) is being evaluated to 0 value?

I compiled the code on a 64-bit machine with gcc as gcc myfile.c. Compiling the code as gcc -W -Wall -ansi -pedantic myfile.c gives warning about the func function, but that's not the point. I am unable to figure out how 8 is the answer.

user47
  • 1,080
  • 11
  • 28
  • 3
    Are you asking why undefined-behavior is not well-defined? This recursive function is very likely to get unrolled and inlined, so start there. – Lundin Jun 02 '23 at 10:18
  • 3
    "8 is the answer" is it? Why not 0 or 9? https://godbolt.org/z/5djEfjxG5 Undefined behavior is undefined. – teapot418 Jun 02 '23 at 10:18
  • 1
    Why *not* return 8? Undefined behavior can do *anything*. It's not like it *can* return an "indeterminate value" (on most systems anyway, where there are no trap codes for integers). – ShadowRanger Jun 02 '23 at 10:20
  • 2
    The function *is* returning a "garbage" value in the case of `func(-1)`. But it just so happens that the returned garbage value will lead to a result of `8` in your specific case and situation and system. – Some programmer dude Jun 02 '23 at 10:21
  • If the result should be "cannot be determined", _you_ need to deal with that. – Jabberwocky Jun 02 '23 at 10:22
  • Folks, I came across this code as a question (kind of things asked in some shitty exams) and *I know the code is bad*. What I don't understand why repeatedly I get only 8 as the value and not something else? I ran the code for 15 minutes. Consistently got 8 as the result. – user47 Jun 02 '23 at 10:23
  • Does this answer your question? [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – ShadowRanger Jun 02 '23 at 10:24
  • 1
    @user47 undefined behaviour is undefined. It is very well possible that the garbage value on your system is consistently 8 for some reason... On my system I consistently get -1867905103 if I compile in release mode and I consistently get 10 in debug mode. – Jabberwocky Jun 02 '23 at 10:24
  • 2
    @user47: Probably put a `-1` in the return value register when no explicit return occurs as a coincidence of how the rest of the code is laid out. Undefined behavior need not be *random* on a per-run basis, but it's likely to differ by compiler, compiler flags, possibly from build-to-build on the same compiler and flags, etc., there is no rule that says what it has to do here, so *any* result is legal. There's no *why* to give you here, because there is no *sense* to what is happening. You didn't tell it what to do, it made no decisions, it just returned without setting a return value. – ShadowRanger Jun 02 '23 at 10:27

2 Answers2

2

A C implementation conforms to the C standard if it obeys all applicable rules of the C standard.

The C standard defines the term “undefined” to mean “this document imposes no requirements” (C 2018 3.4.3).

When a function terminates at its closing } without returning a value but the program attempts to use the return value, the behavior is undefined (C 2018 6.9.1 12). This means there are no requirements on the behavior.

Therefore, for the code you show, there are no requirements on the behavior, so the program conforms to all the rules of the C standard, regardless of what it prints for output or whether it prints anything at all.

In particular, the C standard does not prohibit the program from printing “8”, nor does it require that the program print a number that is weird or large or that looks like “garbage” to you.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

Why garbage value is not being returned in a recursive call to a function with undefined behavior?

Because "garbage" does not mean what you think it means in this context. In particular, "garbage" does not mean "random". (Or if it does, it's more in the sense of xkcd 221.)

Computers are usually deterministic. You have to work pretty hard to get truly random behavior. Even a program that contains the worst kind of undefined behavior will quite often return exactly the same strange and indeterminate number every time you run it.

I have used this analogy:

Suppose you go to the store and buy a brand-new garbage can. But it's completely clean! There's no garbage in it at all! It's so clean you could eat out of it! Was this false advertising? Did the store fraudulently sell you a non-garbage can?

See more discussion at these previous questions: 1 2 3 4 5. (Most of those are talking about the values of uninitialized local variables, not the values of functions that fail to execute a proper return statement, but the arguments are the same.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • That clears it up: *Garbage does not mean random*. – user47 Jun 02 '23 at 10:34
  • 1
    @user47 it can be random-seeming, especially when using uninitialized memory. There is no guarantee that the undefined value will be random, there is none that it will be consistent across runs. There is no guarantee that it will be a value at all, similar code in C++ mode tends to explode into real weirdness (->it fails to print the result: https://godbolt.org/z/14be746YM). – teapot418 Jun 02 '23 at 10:44