0

I recently encountered C code for a function that had the following structure:

int fun1(int x){
    return x + 2;
}
int fun2(int x){
    fun1(x);
}

int main()
{
    printf("%d\n", fun2(5));

    return 0;
}

It seems like there's a missing return statement in function f2:

return fun1(x);

However it works as intended, and the call fun2(5) returns 7. Is this type of implicit return is undefined behaviour, or is it defined and it will work across different compilers and C/C++ standards?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    [It's undefined behavior in C](https://www.wikiod.com/w/C_Undefined_behavior#Missing_return_statement_in_value_returning_function) if trying to use the return value. – yano Nov 01 '21 at 22:16
  • I wonder what compiler let it pass? – tromgy Nov 01 '21 at 22:18
  • the original code i encountered that sparked this question was compiled with gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44) the code posted in my question was compiled and run in onlinegdb:https://www.onlinegdb.com/online_c_compiler i've no idea what compiler they use – Benjamín Panatt Nov 01 '21 at 22:22
  • @tromgy gcc [issues a warning](https://godbolt.org/z/PzzMos5hc) – yano Nov 01 '21 at 22:22
  • 2
    This is different in C and C++, so tagging it with both confuses the issue. Now there is an answer for C but closure as a duplicate of a question for C++. That’s a mess. Do not tag both C and C++ except when asking about differences or interactions between the two languages. – Eric Postpischil Nov 01 '21 at 22:23
  • @EricPostpischil Would this https://stackoverflow.com/questions/4644860 be a good target for the C question? I don't hang out in the C tag often enough to know if there's a better canonical for this. – cigien Nov 01 '21 at 22:26
  • @cigien: I would just vote the question down and delete it. People can already find questions on non-void functions that flow to their ends with separate C and C++ tags, so this one adds nothing to Stack Overflow. What could be useful is to ask a question that specifically asks about the differences between C and C++, tagged with both. That could theoretically be useful for somebody porting old C code to C++ where there is a function with defined behavior in C but not in C++, such as a get/set function (either gets a value and returns it or sets a value and does not, according to a parameter). – Eric Postpischil Nov 01 '21 at 22:39
  • @EricPostpischil No, I meant for future instances, not for this question necessarily. There are occasionally mistagged C questions that I come across, and I just wanted to know if you had a particular canonical you use for those, so I can use that one myself. – cigien Nov 01 '21 at 22:42
  • 1
    @cigien: I do not have a canonical question picked out for this. That one looks okay. At least, some searches I just tried did not reveal a better one. – Eric Postpischil Nov 01 '21 at 22:50
  • @tromgy - Formally, the behaviour is undefined, so no diagnostic is required. Most modern C and C++ compilers do "let it pass" by default, which is valid according to the standards. Most modern compilers routinely do relevant analysis, so can be configured (e.g. command line options to turn up warning levels) to issue warnings/errors in such cases. [Most compilers do NOT diagnose such things by default due to a history of active pressure by developers (who's key measure of performance was "compiling without warnings") on compiler vendors]. – Peter Nov 02 '21 at 00:35
  • @Peter: For clarity, the behavior asked about in the title, returning from a non-void function without returning a value, is not undefined in C. The behavior of the code in the question, attempting to use the return value of a function that did not return a value, is undefined. – Eric Postpischil Nov 02 '21 at 00:39
  • @EricPostpischil Yes, I know. I've also seen some C developers arguing that, because the behaviour is not undefined until the caller uses the return value, that a diagnostic should not be issued within the function since there is no undefined behaviour there (if a diagnostic is issued, they claim it should be issued for the caller and not for the function that causes the problem by falling off the end). At least, in C++, there is no excuse for such an absurd argument (except for the fact of no diagnostic being required for undefined behaviour, which is true in both languages). – Peter Nov 02 '21 at 00:46
  • @Peter: This is an area where it would have been helpful to have a standard means of explicitly indicating that any value a function might return would be just as good as any other, and thus a compiler shouldn't generate code to ensure that any particular value gets returned. If e.g. the Standard had defined a macro `__return_any`, compilers that don't have support for such a construct could have defined it as a macro for `return 0;``, but those that recognize such a construct could have defined it as a compiler intrinsic which could be processed more efficiently. – supercat Nov 02 '21 at 19:06
  • @EricPostpischil: The Standard characterizes as UB actions whose behavior might be impractical to specify on some platforms, even if on many other platforms the behavior would otherwise be unambiguous. A prime example of that is left shifting a negative number, which C89 unambiguously defined on platforms that used two's-complement representations with no padding bits, but which could invoke UB on some platforms which use padding bits. Rather than recognize the behavior as being defined on some platforms, C99 recharacterized it as simply being UB. – supercat Nov 02 '21 at 19:12

1 Answers1

0

This is undefined behavior, at least for C.

It is not permitted to fail to return a value from a function and then attempt to use the return value. This is spelled out in section 6.9.1p12 of the C standard regarding function definitions:

If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.

Note this this means that had you not tried to use the return value, that would not be undefined behavior.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • The only (practical) difference between C and C++ in this case is that behaviour is only undefined in C if the return value is used but, in C++ the act of falling off the end of a non-`void` function is what causes undefined behaviour (except in `main()`, which is a special case). – Peter Nov 02 '21 at 00:40