C variable longevity
Rick Murray (539) 13840 posts |
While I was poking around getting my backtrace to work, I noticed a lot of functions had seemingly random potentially large amounts of space claimed on the stack. After some maths and poking around with *Memory, I figured out that this is for holding local variables. Which brings me to an interesting question. Consider the following code:
The first works. The second does not. The first works because while the stack frame (containing the data) is technically invalid, the strcpy function is a CLib function so leaves the stack alone while it does its stuff. The second fails because once make_string exits (and the stack frame is discarded), calling do_print sets up a new stack frame and trashes what was there before. The result is: */test Called with 1 parameter(s). à€ * Therefore, as I see it, there are two ways to handle this situation: 1. Use globals. As such, it would seem to be “technically impossible” to return any value from a C function where the value is a locally held variable. The C standard suggests: Per C 2011 (N1570) 6.2.4 8, the lifetime of a temporary ends when the evaluation of the full expression (or declarator) containing it ends: “A non-lvalue expression with structure or union type, where the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime.36) Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends when the evaluation of the containing full expression or full declarator ends.” (copied from a forum) However as the value is constructed and held “on the stack”, it doesn’t appear to wait until the full statement that it is a part of has been executed, only until the next function recycles the stack. Is there something I am missing? |
h0bby1 (2567) 480 posts |
aaaaa |
Matthew Phillips (473) 721 posts |
Your make_string function is returning a pointer (char * in this case), and that will be available until the full expression has been evaluated. But what it points to (the string allocated on the stack) is not guaranteed to be there. An alternative to passing a pointer in, and to the malloc option suggested by h0bby1 would be to use a static within the function:
This value will persist as long as you need it. But it is fraught with danger too, because if the function is called again before you use the string, it will get overwritten with a new result. String handling is the biggest nuisance in C. |
Rick Murray (539) 13840 posts |
Perhaps because there is no such thing as a “string” in C? It’s just an array of bytes that happen to resemble strings to certain functions…sometimes (here I am referring to strncpy’s habit of not bothering to return a valid string if the input was too long. Useful…). |
GavinWraith (26) 1563 posts |
Words like “string” and “function” can have utterly different meanings in different programming languages. In Lua strings are immutable values, like numbers. This code looks like the C code superficially: But it works because the semantics of strings are different. It is having those nasty pointers that can become out of date with a change of scope that causes all these difficulties.
|
Rick Murray (539) 13840 posts |
Hehe… The problem with dropping in lots of debug() lines is later on you need to do something with them all. I decided to wrap them in #ifdef … #endif in case I need them again at some future date. ;-) |
David Gee (1833) 268 posts |
Strings in Java are also immutable. You have to be careful if doing a lot of reassignment of strings (e.g. Adding something to the end of a string) in Android because of the impact of all the reallocations on performance. |
GavinWraith (26) 1563 posts |
The solution is to use not strings but ropes, i.e. trees whose leaves are strings. A good way to think of them is as strings with holes in them, ready to accept more strings with holes. Very often a program to create a document ends up by writing it out to a file; in that case you may never need to concatenate strings. You simply walk the tree, writing out the leaves. This strategy gives much faster performance. Ideally you need a rope library which generalizes the usual things you need to do on strings, such as pattern matching, so that they work on ropes. |