What happens if you don't return a value in C+

2019-02-03 06:47发布

Yesterday, I found myself writing code like this:

SomeStruct getSomeStruct()
{
    SomeStruct input;

    cin >> input.x;
    cin >> input.y;
}

Of course forgetting to actually return the struct I just created. Oddly enough, the values in the struct that was returned by this function got initialized to zero (when compiled using g++ that is). Is this just a coincidence or did another SomeStruct get created and initialized somewhere implicitly?

6条回答
唯我独甜
2楼-- · 2019-02-03 07:18

The calling conventions for most modern CPU architectures specify a particular register to pass a function return value back to the caller. The caller makes the function call, and then uses the specified register as the return value. If you do not explicitly return a value, the caller will nonetheless use whatever garbage happens to be in that register.

The compiler will also use all registers it has available for internal computation within the function. The register designated for holding the return value will also be used for misc computation within the function. Thus when you forget to specify a return value it is not unusual to find the correct value has miraculously been returned to the caller: the compiler used that register to store your object.

Unfortunately even a trivial change to the function can cause the register allocation to change, so the return value becomes true garbage.

查看更多
来,给爷笑一个
3楼-- · 2019-02-03 07:19

Did another SomeStruct get created and initialized somewhere implicitly?

Think about how the struct is returned. If both x and y are 32 bits, it is too big to fit in a register on a 32-bit architecture, and the same applies to 64-bit values on a 64-bit architecture (@Denton Gentry's answer mentions how simpler values are returned), so it has to be allocated somewhere. It would be wasteful to use the heap for this, so it has to be allocated on the stack. But it cannot be on the stack frame of your getSomeStruct function, since that is not valid anymore after the function returns.

The compiler instead has the caller tells the called function where to put the result (which is probably somewhere on the stack of the caller), by passing the called function a hidden pointer to the space allocated to it. So, the place where it is being set to zero is on the caller, not on your getSomeStruct function.

There are also optimizations like the "named value return optimization" where extra copies can be elided. So, had you used the missing return, the result would be created directly on the space allocated by the caller, instead of creating a temporary and copying it.

To know more about what is happening, you have to look at the caller function. Is it initializing (to zero) an "empty" SomeStruct to which you later assign the return value of your getSomeStruct function? Or is it doing something else?

查看更多
Viruses.
4楼-- · 2019-02-03 07:28

For me the compiler didn't allow it: http://codepad.org/KkzVCesh

查看更多
太酷不给撩
5楼-- · 2019-02-03 07:35

Falling off the end of a function that is declared to return a value (without explicitly returning a value) leads to undefined consequences. For gcc, you should start with the -Wall command line switch that turns on most useful warnings. The specific gcc warning that controls the warning you want is -Wreturn-type (which is included in -Wall, I just mention this for completeness).

Once you have warnings turned on, you should also use -Werror to treat warnings as errors and make the build stop at the point it detects an error.

查看更多
叛逆
6楼-- · 2019-02-03 07:35

You didn't get any warning because you didn't have -Wall -Werror turned on. (As stated in other answers)

However I think you probably got a zero-filled struct as the result because the stack object was default constructed in the caller function, possibly with explicit zero arguments, or else due to zeros on the stack?

查看更多
干净又极端
7楼-- · 2019-02-03 07:39

I find this interesting. With default options used, the following compilers have the following behavior when compiling the GetSomeStruct() function:

  • Microsoft VC, all versions (since VC6 anyway):

    error C4716: 'getSomeStruct' : must return a value

  • Digital Mars:

    Warning 18: implied return of getSomeStruct at closing '}' does not return value

  • Comeau:

    warning: missing return statement at end of non-void function "getSomeStruct"

  • gcc:

    no error or warning

Given the following couple of sentences from the standard (6.6.3 Paragraph 2):

A return statement without an expression can be used only in functions that do not return a value, that is, a function with the return type void, a constructor (12.1), or a destructor (12.4). ... Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

I would say there's little reason for a compiler not to give an error in this case. Why do so many compilers give only a warning or no diagnostic at all?

查看更多
登录 后发表回答