2

I'm not a C programmer by trade but I've been getting more interested recently. As I understand it, in C function arguments are passed by value so that explains why v1 is unchanged.

The thing I don't understand is why v2 has the correct value after the stack_copy returns. My understanding is that function args are put on the stack and should be dealloacted at the end of of the function scope and so I would expect v2 to contain junk.

What's going on here?

Note: I tested this in c using the Visual Studio 2015 compiler on Windows and clang on OSX.

#include "assert.h"

typedef struct {
    int x;
    int y;
    int z;
} Vec3;

Vec3 stack_copy(Vec3 v) {
    v.x = 3;
    v.y = 3;
    v.z = 3;

    return v;
}

int main() {
    Vec3 v1 = {7, 7, 7 };
    Vec3 v2 = stack_copy(v1);

    assert(v1.x == 7 && v1.y == 7 && v1.z == 7);
    assert(v2.x == 3 && v2.y == 3 && v2.z == 3);

    return 0;
}
kontrarian
  • 558
  • 2
  • 7
  • 16
  • 1
    Not really a duplicate (if you stress the returning), but please read this Q/A and elaborate your question. I.e. elaborate the parts which you do understand and focus the qustion on the part you don't. https://stackoverflow.com/questions/29088971/parameter-passing-in-c-pointers-addresses-aliases – Yunnosch Mar 31 '18 at 06:55
  • 4
    Arguments are passed by value, and return values are returned by value too. It doesn't matter if `v` is deallocated. – user2357112 Mar 31 '18 at 06:57
  • Based on above link, it basically is the fact that in addtion to the "call by value" happening to the parameter on the way in, there is something of a "return by value" (i.e. the value get copied) on the way out. – Yunnosch Mar 31 '18 at 06:57
  • Possible duplicate of [Is it safe to return a struct in C or C++?](https://stackoverflow.com/questions/9590827/is-it-safe-to-return-a-struct-in-c-or-c) – Jean-Baptiste Yunès Mar 31 '18 at 07:24

3 Answers3

2

I assume you are aware of the concept of "call by value" in C, i.e. you are not asking about the parameter seeming to be a reference (C++-style).
Otherwise her is a good Q/A on the topic Parameter Passing in C - Pointers, Addresses, Aliases

Your focus in this question is on the returning of the value of struct type.
The same happens "on the way out", i.e. copying the value back to whatever the return value of the function gets assigned to.

This is not different for struct type values than for any other.

I assume that your question did not occur to you when looking at this example:

int stack_copy(int v) {
    v = 3;

    return v;
}
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
1

You a returning by value just like you passed by value. Of course parameter v is deallocated (at least semantically because compiler may optimise this with RVO return value optimisation) but its value is returned and copied in v2. Defining a type defines its possible values, and for a struct it is the cartesian product of its element types. So returning a Vec3 is just returning a pack of three integers.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

You are right, local variables are allocated on the stack.

When you call the method, a copy of v1 is pushed into the stack, and all the following manipulations change that exact object.

But, the compiler does an additional step to allow non primitive return values (structs): When calling the method an additional pointer is passed. It points to an address from the caller's stack, and the return value is written directly to that address. This also prevents additional copies and is referred to as "return value optimizations".

Daniel Trugman
  • 8,186
  • 20
  • 41