| CodeGuru Home | VC++ / MFC / C++ | .NET / C# | Visual Basic | Newsletters | VB Forums | Developer.com |
|
|||||||
| C++ (Non Visual C++ Issues) Ask or answer C and C++ questions not related to Visual C++. This includes Console programming, Linux programming, or general ANSI C++. |
![]() |
|
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
#1
|
||||
|
||||
|
Stack allocation routines
Why aren't there any standard stack allocation routines? An answer could be that stack is an implementation terminology that might not hold relevance on certain platforms and hence, allocation routines that would be based on it are not standardized. But if that is the case, are there any practical implementations (OS or Compiler) that do not relate to a stack as a concept? If there are, how do they handle normal automatic variable allocations, function call stack and exception handling? Is that alternative efficient enough as compared to dynamic allocations?
__________________
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold My Blogs : Learning C++ is fun | Abnegator's reflectionsOpen Threads : C++ Aha! Moments | Nature of work in C++? |
|
#2
|
|||
|
|||
|
Re: Stack allocation routines
I know some compilers for microcontrollers that may allocate memory without relation to stack. One example is 8051. Keil C compiler can use on-chip and out-chip RAMs or even registers to store parameters and local auto variables. But the stack concept still exists. Stack is a hardware concept. You may read books on computer architecture or assembly language to get aware of it. The allocation process is to modify the registers relevant to stack, such as EBP. However, dynamic allocation(heap or memory pool) in any platform is expensive, for the sake of concurrency and protection.
|
|
#3
|
||||
|
||||
|
Re: Stack allocation routines
Quote:
For example, on i386 architecture, it is not possible to have a stack allocation routine, allocating a variable amount of memory, without some specific stack frame model. It means that, though it's possible on i386, compilers that disable or detect the absence of such allocation can produce better code. Another problem: There are probably platforms on which such allocation mechanism would be quite impossible or dramatically reduce performances. For example, on 6502 CPU (which has not more than 256 bytes of stack), it would be quite impossible to do it... Except if the allocation of "dynamic stack data" is not done on the real stack, but on a separate, independent stack. I think that many CPU would require such workaround. So, why would you want it? It's better to write a class encapsuling these operations. Furthermore, dynamic allocation on the stack (if and only if the same stack is used for function calls) is very unsafe, since you can't know how much stack space you'll ever use, and the stack overflow condition may occur after the allocation itself, and when a function is called.... Assuming that the standard require compilers for throwing software exceptions when a stack overflow condition occur: 1) It would require a lot of checking code on some platforms (except if this stack is managed separately), dramatically reducing performances. 2) It would produce unrecoverable exceptions... Since, *any* function call or perhaps worst... any statement using temporary variables... would become a potentially throwing operation! Consequently, it would become impossible to write exception safe code (no-throw operations are necessary for exception safety).
__________________
"inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards. Club of lovers of the C++ typecasts cute syntax: Only recorded member. Out of memory happens! Handle it properly! Say no to g_new()! |
|
#4
|
|||||||||
|
|||||||||
|
Re: Stack allocation routines
First off, thanks to Jim_King_2000 and SuperKoko for taking your time and responding.
Quote:
Quote:
Quote:
Quote:
![]() Quote:
Quote:
Quote:
Quote:
Quote:
I am more interested in finding out why implementing something like this could be tough? Basically, standardization, which means across all platforms. There can be two possibilities: 1. There is a stack but dynamic stack allocation is problematic - I want to find out why/how? 2. There is no stack - but then in this case how and where do they allocate automatic (or stack based) variables/objects.
__________________
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold My Blogs : Learning C++ is fun | Abnegator's reflectionsOpen Threads : C++ Aha! Moments | Nature of work in C++? |
|
#5
|
|||||||
|
|||||||
|
Re: Stack allocation routines
Quote:
For now, I can only see low-level definitions of stack, heavily relying on assembly-level concepts that the standard should never mention. There are perhaps possibilities to define this word with a high-level meaning, but I doubt it'll ever be a useful concept. On the other side, it is easy to define a "stack-allocating function" such as the alloca supported by a few compilers, because it doesn't require defining the word "stack". Quote:
Quote:
Code:
int func(size_t n) {
int x=42; // assume it's not put in a register.
char* p=(char*)dynamically_allocate_on_the_stack(n);
return x;
};
Code:
func: sub esp,8 mov dword ptr [esp+4], 42 ; assigns a value to x sub esp, [esp+12] ; dynamically allocates the stuff mov [esp+???], esp ; assign that to p mov eax,[esp+???] ; loads x add esp, ??? ; where could we store the amount of stack used? ret He can't know.... Because the stack space is variable. If there is only static allocation on the stack, the compiler has no problem. It is possible to work around this problem, using the ebp register for addressing the stack space: Code:
func: push ebp ; needs to save this register mov ebp, esp ; this register is now reserved for this usage (1 register lost on the very few registers of the i386) sub esp,8 ; stack space for x and p mov [ebp-4], 42 ; assigns 42 to x sub esp, [esp+8] ; allocates space on stack mov [ebp-8], esp ; assigns it to p mov eax, [ebp-4] ; loads x mov esp, ebp pop ebp ; clean up stack frame ret 2) a register is condemned. Quote:
The 6502 has no direct mean to decrement the stack pointer by an arbitrary number, and it has no mean to access memory relative to the stack pointer except the element on the top of the stack. It has only a call/ret/push/pop mechanism, plus instructions to move the stack pointer into the X register or the X register into the stack pointer. So, in fact, the workaround equivalent to the use of ebp on i386, would require storing the address of S when the function is entered (because there are only very very few registers, we can't condemn any of them), somewhere in the page zero, and access the stack with indirect accesses, not only for the dynamically allocated data, but for any variable on the stack... Furthermore, putting this "dynamic stack allocation" elsewhere than in the hardware stack, would not increase this penalty for dynamic stack allocation, but would avoid the very serious performance penalty on the hardware stack. So, my point is that, the hardware stack must not be used here. There can be a software stack for dynamic allocation, but it will be equivalent to a library stack. Quote:
Quote:
It can be stored in another register, on some platforms... It must be stored at a static place in memory on other platforms. Even the old K&R C prototype-free functions (thus, requiring the caller to clean up the stack frame) are problematic and tough to implement on many platforms. http://cm.bell-labs.com/cm/cs/who/dmr/clcs.html Fortunately, this problem nowadays, exists only with variadic parameter functions. Prototype-free functions or variadic argument functions are far less problematic to implement than dynamic allocation on the stack. Quote:
There may be a stack, not being the hardware stack. For example, suppose that an interpretor wants to let the user use many recursive functions... a std::deque might be an adequate container for that.... But, it is not possible to allocate an arbitrary large contiguous chunk on a std::deque or any similar data structure. Another, very possible scenario: a stack formed of pointers (all of the same size) to objects of an internal Variable class type. This stack would only store pointers to the heap, and dynamic allocation on the stack itself would not be possible, though a feature such as alloca would well be possible... Allocating on the heap, of course. Conclusion: alloca-like functions are implementable in an efficient way... But, most of the time, it would not allocate the stuff on the hardware stack, but on a separate software stack or on the heap.... Even if the standard would say that this function must allocate on a "hardware stack" (I don't see how the standard could define this term), the as-is rule would imply that compilers are free to implement it as they can, out of the hardware stack. Anyway, I don't think it would give any feature that we don't already have... It's easy to write a library for software stack allocation. And, on computers where it is possible to efficiently dynamically allocate on the hardware stack (or on a software stack), compilers writers are free to allocate the room for automatic std::vector variables on this stack if they can prove that it makes no difference.
__________________
"inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards. Club of lovers of the C++ typecasts cute syntax: Only recorded member. Out of memory happens! Handle it properly! Say no to g_new()! Last edited by SuperKoko; November 26th, 2006 at 03:38 PM. |
|
#6
|
||||
|
||||
|
Re: Stack allocation routines
Quote:
|
|
#7
|
|||
|
|||
|
Re: Stack allocation routines
Stack is LIFO(last in, first out). And many CPUs implement it by means of hardware. Of course you can implement it by software(such as STL::stack). However, CPUs and compilers use the first one to store local variables. On Windows, you can employ "_alloca" to allocate stack memory dynamically, and the memory allocated by this way will be deallocated automatically. This method need a function which is not belong to ANSI C, so I don't think it would work on other platforms. So, I think you should find some substitutions.
|
|
#8
|
|||
|
|||
|
Re: Stack allocation routines
For the reason to not providing stack dynamic operations within ANSI, I think:
1. It's not permanent. The stack will vary with function calls and returns. So if you store something in stack, and then you call some functions or some functions return, the content of which you stored may change, even the space is never belong to you. So you must use "_alloca" locally and carefully. 2. It's not safe. Many important data(including function return address) are stored in stack. So manipulations of stack will cause a lot of system errors such as invalid memory access, stack overflow, thread crash, etc. 3. It's not necessary. You can use local auto array variables, or memory pool. Why do you love dynamic stack allocation so much? Last edited by Jim_King_2000; November 26th, 2006 at 10:36 PM. |
|
#9
|
||||
|
||||
|
Re: Stack allocation routines
Personally I can see no reason why a compiler should not be able to cope with:
Code:
void f(size_t n)
{
int arr[n];
// ...
}
On systems where it can live on the stack, it could be more efficient than std::vector. Last edited by Zaccheus; November 27th, 2006 at 03:52 AM. |
|
#10
|
||||
|
||||
|
Re: Stack allocation routines
Yeah, that is what is my reason for asking about it. Had it been possible, we could have had variable length fixed arrays in C++ directly without relying on the free store to keep the allocation.
This question of mine has source from one of the discussions that I came across on comp.lang.c++.moderated. The problem with std::vector is that, it is not possible to lock it's inherent "growable" property. And hence it sometimes becomes tough to have multi-dimensional arrays or even single dimensional arrays which should in fact be arrays with fixed size (known at runtime) and don't grow and also provide auto-cleanup. Moreover, vector of vector is actually jagged and not contiguous. (Let's not discuss for the moment if vector of vector is the right choice for implementing 2-D arrays) and you can't restrict one of the rows to grow more than others. One can surely craft a class encapsulating this logic and allocating using new, but that would be on the heap. I had a feeling if it had direct support for allocation on stack, it would be better. I am not sure what implementations are used for C's VLA's and if it is efficient and portable. alloca routines provided by gcc and vc++ are closer match but I guess they are platform dependent extensions.
__________________
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold My Blogs : Learning C++ is fun | Abnegator's reflectionsOpen Threads : C++ Aha! Moments | Nature of work in C++? Last edited by exterminator; November 27th, 2006 at 06:13 AM. |
|
#11
|
||||||||
|
||||||||
|
Re: Stack allocation routines
Quote:
Quote:
I know that many people are tempted to add into their language a builtin feature for each of the specific feature that his favorite platforms (such as SIMD) supports. That's very bad for the long term.... Because hardware changes and those features would become more and more emulated while newer ones would appear and the language will finally become a huge heap consisting of all the CPU features of all existing platforms (+ platforms of the past)... Fortunately, the C and C++ standard maintain a level of abstraction, avoiding hardware details. SIMD and other things, should be handled by the optimizer, not the programmer... It guarantees that C++ will remain portable to several platforms and for a long time. Quote:
Quote:
Quote:
VLA don't solve this problem either, except if you're refering to the proposal of Dennis Ritchie... Which is unrelated to stack and inadequate for C++ because classes better handle the issue. Quote:
And if a heap can't be fast enough, why wouldn't you write a stack class and create a single instance of it (or one instance for each thread)? It would be perhaps more efficient than using alloca! It would be exception-safe. Moreover a not-too-bad heap, the CPU time consumed by allocation/deallocation is very small, especially for large memory blocks such as 2D matrices. Quote:
Quote:
I hope you don't use setjmp()/longjmp() often. Do you? If you want, you can propose a stack allocation class as a library extension. I don't think C++ is a weak language that needs to be filled of abstraction-lacking features. C++ is powerful enough to be extended by libraries. PS: Adding any feature to C++ has a cost: forward-compatibility is almost as useful as backward-compatibility.
__________________
"inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards. Club of lovers of the C++ typecasts cute syntax: Only recorded member. Out of memory happens! Handle it properly! Say no to g_new()! Last edited by SuperKoko; November 27th, 2006 at 07:22 AM. |
|
#12
|
||||
|
||||
|
Re: Stack allocation routines
Quote:
Last edited by Zaccheus; November 27th, 2006 at 05:27 PM. |
|
#13
|
||||
|
||||
|
Re: Stack allocation routines
Quote:
It is partly due to history & the fact that arrays are manipulated through pointers and have not special runtime size information. For example, if arrays whose length is not known at compile time, were used in multidimensional arrays, it would become very complex for the compiler to handle those things. C99 VLA are a very ugly, inconsistent, and are recognized as being a hack to avoid the painful usage of malloc()/free() in C where there is no std::vector class. C99 VLA are hacks. Real arrays (having a real type, known at compile time) are not hacks. If arrays had to be variable in length, Dennis Ritchie's proposal (whose link is available in one of my previous post) would have been 10 times more meaningful, and close to the real problem. Anyway, C99 VLA are easy to implement on all hardware because they're not guaranteed to put the stuff on the stack... So, they can use the heap and can be as portable as the heap itself (excluding the setjmp/longjmp issue). In C++, C99 VLA are absolutely meaningless and inappropriate... except for compatibility with C99.
__________________
"inherit to be reused by code that uses the base class, not to reuse base class code", Sutter and Alexandrescu, C++ Coding Standards. Club of lovers of the C++ typecasts cute syntax: Only recorded member. Out of memory happens! Handle it properly! Say no to g_new()! |
|
#14
|
||||||
|
||||||
|
Re: Stack allocation routines
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
|
![]() |
| Bookmarks |
|
||||||
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|