0

This is just to clarify some confusions that I've had for quite a while in C/C++: if my understanding is correct...is it true that in C/C++ you can return a local struct by value (copy) from a function, but not a local array? For example (my understanding of events has been stated in the comments with ? indicating an assertion I'm not entirely confident of making):

#include <stdio.h>

struct my_structure { int x; int y; };

struct my_structure foo(int a, int b)
{
    // declare struct variable (will allocate 4 + 4 bytes on foo()'s stack frame for 2 ints)
    struct my_structure ms;

    // do some kind of processing on the struct variable; just for example, let's say...
    ms.x = a*a;
    ms.y = b*b;

    // ? return by value: will COPY the 4 + 4 bytes into caller (main)
    return ms; 
}

int main() {
    struct my_structure retval; // will allocate 4 + 4 bytes on the main()'s stack frame
    retval = foo(10, 20); // ? will copy foo()'s local struct `ms` into the 4 + 4 bytes allocated in above declaration
    printf("%d, %d\n", retval.x, retval.y); // 100, 400
}

If I'm not wrong, in the above code sample, there is no question of returning any kind of an address---everything is being dealt with purely in terms of values and copying, so returning structs this way should be safe, although not efficient for large structs.

Now coming to function-local arrays, I have gone through some posts (such as this) saying that you cannot return a local array from a function. What I want to know is the reason why you cant just copy the array values byte-wise like you can with structs from the called function's stack to the caller's (as in the above code example)?

This is my guess: when you return an array by name, the C/C++ compiler implicitly converts the name to a pointer to the first element (array to pointer decay?) so instead of returning a copy you end up returning the base address to an array which, when the variable goes out of scope, won't point to anything (this is very bad and thus should not be done). This is not the case with structs, where returning a struct variable by name, simply returns the struct variable as a copy (no decaying to pointer whatsoever). Am I correct or is my understanding flawed? Any suggestions are welcome. Thank you.

EDIT: MY question is mostly aimed at C, but because C++ is supposed to be a superset, I'm assuming it would apply to C++ as well?

A-T
  • 342
  • 2
  • 14
First User
  • 704
  • 5
  • 12
  • 5
    Your understanding is more or less correct. – Jabberwocky Feb 28 '23 at 17:44
  • 1
    Related/possible duplicates: [Why we can directly copy pointers, but we can not directly copy arrays in c++](https://stackoverflow.com/q/12896727/11082165), [Why doesn't C++ support functions returning arrays?](https://stackoverflow.com/q/5157439/11082165) – Brian61354270 Feb 28 '23 at 17:47
  • 5
    Please note that there's no such languages like "C/C++". C and C++ are two *very* different languages, and even things that might seem like they should be similar often are not. For example C *only* have pass by/return by value, nothing else. – Some programmer dude Feb 28 '23 at 17:47
  • 1
    it is possible via `struct my_array { int x[42];};` or `std::array`. Don't try to understand arrays by applying logic and common sense, they are weird :) – 463035818_is_not_an_ai Feb 28 '23 at 17:48
  • 1
    you can return a local std::array – jls28 Feb 28 '23 at 17:48
  • 2
    _"because C++ is supposed to be a superset"_ may have some historical truth, but isn't at all true for today's C++. C and C++ are two separate languages. There are C programs that can't be compiled as C++ programs, as well as C programs that can be compiled as C++ programs but which _do different things when compiled as C++_ – Brian61354270 Feb 28 '23 at 17:49
  • 2
    I think you're correct. Do note that you can return constant sized arrays when wrapped in a struct (to avoid pointer decay)... i.e. `struct foo_s { uint32_t u32[4]; }` – Myst Feb 28 '23 at 17:49
  • See also [What does impossibility to return arrays actually mean in C?](https://stackoverflow.com/questions/50808782) – Steve Summit Feb 28 '23 at 18:18
  • 1
    The answer is basically *"Because the standard says so"* They could have made it impossible to return structs. They could have made it possible to return arrays. However, it IS possible to return an array if you wrap it in a struct. `struct wrapper { int arr[10]; }` – klutt Feb 28 '23 at 18:40
  • 1
    _Side note:_ It's bad practice to pass structs _by value_ (or return them _by value_) if they're non-trivial. When returning one (e.g.) `struct mystruct str = func();`, the compiler must allocate a hidden/implied area on the stack. The return data is placed there. Then, it gets copied to `str`, so lots of unnecessary copying. Also, it doesn't scale. To see this, add `int junk[1000000000];` to the struct definition. Using pointers this is okay, but doing by value blows up the stack. – Craig Estey Feb 28 '23 at 18:46

2 Answers2

2

why you cant just copy the array values byte-wise like you can with structs from the called function's stack to the caller's ...

C could have allowed this - and did.

Some early C compilers allowed it - sorta.

struct my_struc { int x[42]; };
struct my_struc foo();

int y[42];
y = foo().x;

Yet today C does not allow copying arrays with a =.


Today, code can copy an array inside a struct by copying the struct.

struct my_struc z = foo();

Have fun explaining why you need to do this in the code review.


As to why, I suspect that since it was considered a poor practice, no need to support it.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

is it true that in C/C++ you can return a local struct by value (copy) from a function, but not a local array?

It is true in C. C++ is a different language, but I'm pretty sure it's also true there. C++ is not a superset of C, but they have a shared heritage and a common subset. It is not safe in general to assume that statements that are true about C are also true about C++, or vice versa.

If I'm not wrong, in the above code sample, there is no question of returning any kind of an address---everything is being dealt with purely in terms of values and copying, so returning structs this way should be safe, although not efficient for large structs.

C semantics permit copying structs, including returning them. This means copying struct values, not their addresses. No aliasing occurs, and if the copy is stored in an object, then that object has its own lifetime, independent of that of the source object, if any.

Now coming to function-local arrays, I have gone through some posts (such as this) saying that you cannot return a local array from a function. What I want to know is the reason why you cant just copy the array values byte-wise like you can with structs from the called function's stack to the caller's (as in the above code example)?

Who's "you"? The design of the C language doesn't work like that. It could have done, but it does not. You cannot even express it in C (or in C++), because expressions of array type are automatically converted ("decay") to pointers to the first array element in most contexts, including when they appear as function arguments or in return statements. This is more or less as you hypothesized. And yes, such a pointer ceases to be valid when the lifetime of the object to which it points ends. For an automatic object, that's no later than the termination of the function execution during which it was allocated.

However, you can certainly perform such copying via, say, the memcpy() function. You just need the address to which the data should be copied, and the size of the data, and you must do it during the overlap of the lifetime of the source and destination objects.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157