Is it safe to return a structure in C or C ++?

I understand that this should not be done, but I believe that I have seen examples that do something like this (note code is not necessarily syntactically correct, but there is an idea)

typedef struct{ int a,b; }mystruct; 

And then here is the function

 mystruct func(int c, int d){ mystruct retval; retval.a = c; retval.b = d; return retval; } 

I realized that we should always return a pointer to the malloc'ed structure if we want to do something like this, but I'm sure I saw examples that do something like this. It's right? Personally, I always either return a pointer to the malloc'ed structure, or simply pass a reference to the function and change the values ​​there. (Since I understand that once the scope of the function is finished, any stack used to allocate the structure can be overwritten).

Add the second part of the question: does it depend on the compiler? If so, what is the behavior of the latest desktop compilers: gcc, g ++, and Visual Studio?

Thoughts on this?

+68
c ++ c function struct return-type
Mar 06 2018-12-12T00:
source share
11 answers

It is completely safe, and it is not. In addition: it is not dependent on the compiler.

Usually, when (for example, your example) your structure is not too large, I would say that this approach is even better than returning the malloc'ed structure ( malloc is an expensive operation).

+66
Mar 06 2018-12-12T00:
source share

It is completely safe.

You return by value. Which would lead to undefined behavior if you came back by reference.

 //safe mystruct func(int c, int d){ mystruct retval; retval.a = c; retval.b = d; return retval; } //undefined behavior mystruct& func(int c, int d){ mystruct retval; retval.a = c; retval.b = d; return retval; } 

The behavior of your fragment is completely correct and defined. It does not depend on the compiler. This is normal!

Personally, I always return a pointer to the malloc'ed structure

You should not. You should avoid dynamically allocated memory if possible.

or just follow the link to the function and change the values ​​there.

This option works great. This is a matter of choice. In general, you do this if you want to return something else from the function, changing the original structure.

Because I understand that as soon as the scope of a function is more than that, whatever stack is used to distribute the structure, it can be overwritten

It is not right. I meant that this is correct, but you are returning a copy of the structure that you create inside the function. Theoretically . In practice, RVO can and is likely to happen. Read the optimization of the return value. This means that although the retval function goes out of scope when the function ends, it can actually be created in the calling context to prevent an extra copy. This is an optimization that the compiler can implement.

+60
Mar 06 2018-12-12T00:
source share

The lifetime of the mystruct object in your function really ends when you leave the function. However, you pass the object by value to the return statement. This means that the object is copied from the function to the calling function. The original object has disappeared, but the copy lives.

+7
Mar 06 2018-12-12T00:
source share

This is completely legal, but with large structures, two factors must be considered: speed and stack size.

+4
Mar 06 2018-12-12T00:
source share

Not only is it safe to return a struct in C (or a class in C ++, where struct -s are actually class -es with default elements public: , but a lot of software does this.

Of course, when class returned to C ++, the language indicates that some kind of destructor or moving constructor will be called, but there are many cases where this can be optimized by the compiler.

In addition, Linux x86-64 ABI indicates that returning a struct with two scalars (for example, pointers or long ) values ​​are done through registers ( %rax and %rdx ), so it is very fast and efficient. Therefore, for this particular case, it is probably faster to return such two-scalar struct fields than to do anything else (for example, store them in a pointer passed as an argument).

Returning such a bi-scalar struct is much faster than malloc , and returns a pointer.

+4
May 16 '15 at 7:11
source share

The type of the structure may be the type for the value returned by the function. This is safe because the compiler is going to create a copy of the structure and return the copy, not the local structure to the function.

 typedef struct{ int a,b; }mystruct; mystruct func(int c, int d){ mystruct retval; cout << "func:" <<&retval<< endl; retval.a = c; retval.b = d; return retval; } int main() { cout << "main:" <<&(func(1,2))<< endl; system("pause"); } 
+3
Mar 06 '12 at 20:10
source share

It is completely safe to return the structure as you did.

Based on this statement, however: since I understand that once the scope of a function is complete, any stack used to distribute the structure can be overwritten, I would only imagine a scenario in which any of the members of the structure was dynamically allocated (malloc'ed or new'ed), and in this case, without RVO, dynamically allocated elements will be destroyed, and the returned copy will have a member indicating garbage.

+3
Mar 06 '12 at 20:18
source share

Security depends on how the structure itself was implemented. I just stumbled upon this question by implementing something similar, and here is a potential problem.

When returning the value, the compiler performs several operations (among, possibly, others):

  • Invokes the copy constructor mystruct(const mystruct&) ( this is a temporary variable outside the func function allocated by the compiler)
  • calls the ~mystruct destructor for the variable that was allocated inside func
  • calls mystruct::operator= if the return value is assigned to something else with =
  • calls the ~mystruct destructor in the temporary variable used by the compiler

Now, if mystruct is as simple as described here, everything is fine, but if it has a pointer (e.g. char* ) or more complex memory management, it all depends on how mystruct::operator= , mystruct(const mystruct&) , and ~mystruct . Therefore, I offer warnings when returning complex data structures as a value.

+3
May 31 '13 at 8:08
source share

I also agree with sftrabbit, Life does end, and the stack area is cleared, but the compiler is smart enough to ensure that all data must be received in registers or in some other way.

Below is a simple confirmation example (taken from the Mingw compiler assembly)

 _func: push ebp mov ebp, esp sub esp, 16 mov eax, DWORD PTR [ebp+8] mov DWORD PTR [ebp-8], eax mov eax, DWORD PTR [ebp+12] mov DWORD PTR [ebp-4], eax mov eax, DWORD PTR [ebp-8] mov edx, DWORD PTR [ebp-4] leave ret 

You can see that the value of b was passed through edx. while eax defaults to.

+2
Mar 06 2018-12-12T00:
source share

Invalid return structure. I like to do this on my own, but if someone later adds a copy constructor to the returned structure, the copy constructor will be called. This may be unexpected and may break the code. This mistake is very difficult to find.

I had a more complicated answer, but the moderator did not like it. So, at your expense, my advice is short.

+1
Aug 10 '13 at 18:17
source share

Add the second part of the question: does it depend on the compiler?

Indeed, this happens when I discovered my pain: http://sourceforge.net/p/mingw-w64/mailman/message/33176880/

I used gcc on win32 (MinGW) to invoke COM interfaces that returned structures. It turns out that MS does this differently with GNU, and so my (gcc) program crashed with a broken stack.

Maybe MS may have a higher rating here, but all I care about is ABI compatibility between MS and GNU for building on Windows.

If so, what is the behavior of the latest desktop compilers: gcc, g ++, and Visual Studio

You can find some messages on the Wine mailing list about how MS does this.

+1
Dec 24 '14 at 3:48
source share



All Articles