None of what you ask can be done in standard c++ since the stack is not specified in the standard.
You may be able to access that information by reading cpu registers in assembly language. How to do that depends on the cpu architecture, the OS and possibly the calling convention used by the compiler. Best place to find the information you're looking for is the manual for the architecture, OS, etc. The platfrom may also provide the information through system calls or virtual filesystems.
As an example, here's a quick look at the wikipedia page for the common x86 architecture
SP/ESP/RSP: Stack pointer for top address of the stack.
BP/EBP/RBP: Stack base pointer for holding the address of the current stack frame.
You can unwind the stack and find find the top of the stack in the first call frame. How to unwind the stack is again, specific to calling convention used. Subtracting the base of the first stack frame with the current stack pointer would give you the current size of the stack. Also remember that each thread has their own call stack so you must subtract from the bottom of the stack of the correct thread.
But keep in mind that:
Although the main registers (with the exception of the instruction pointer) are "general-purpose" in the 32-bit and 64-bit versions of the instruction set and can be used for anything...
You should check the manual of your target platform before assuming what the registers are used for.
Getting the remaining / total maximum stack space can be a bit trickier. In Linux the stack size is typically limited during runtime. The limit can be accessed through the /proc/ filesystem or using system calls. In Windows, the maximum stack size can be set at linktime and should be accessible in the executable file headers.
Below is an example program that works on Linux. I read the start of stack from /proc/<pid>/stat. I also provide an example for unwinding and for that I use a library that abstracts away all the OS / architecture specific assembly code. The stack is unwound all the way up to the initialization code before main and the stack space used by that is accounted for.
I use SP register instead of BP to get the bottom of the stack in the fisrt call frame because BP does not exist in some architectures and on my platform it was zero in the initialization frames. That means that the bottom is off by the size of the first call frame and is therefore just an approximation. See it on coliru, unfortunately access to /proc/<pid>/stat is denied there.
#include <iostream>
using namespace std;
#include <fstream>
#include <sstream>
#include <unistd.h>
// read bottom of stack from /proc/<pid>/stat
unsigned long bottom_of_stack() {
unsigned long bottom = 0;
ostringstream path;
path << "/proc/" << getpid() << "/stat";
ifstream stat(path.str());
// possibly not the best way to parse /proc/pid/stat
string ignore;
if(stat.is_open()) {
// startstack is the 28th field
for(int i = 1; i < 28; i++)
getline(stat, ignore, ' ');
stat >> bottom;
}
return bottom;
}
#include <sys/resource.h>
rlim_t get_max_stack_size() {
rlimit limits;
getrlimit(RLIMIT_STACK, &limits);
return limits.rlim_cur;
}
#define UNW_LOCAL_ONLY
#include <libunwind.h>
// using global variables for conciseness
unw_cursor_t frame_cursor;
unw_context_t unwind_context;
// approximate bottom of stack using SP register and unwinding
unw_word_t appr_bottom_of_stack() {
unw_word_t bottom;
unw_getcontext(&unwind_context);
unw_init_local(&frame_cursor, &unwind_context);
do {
unw_get_reg(&frame_cursor, UNW_REG_SP, &bottom);
} while(unw_step(&frame_cursor) > 0);
return bottom;
}
// must not inline since that would change behaviour
unw_word_t __attribute__((noinline)) current_sp() {
unw_word_t sp;
unw_getcontext(&unwind_context);
unw_init_local(&frame_cursor, &unwind_context);
unw_step(&frame_cursor); // step to frame before this function
unw_get_reg(&frame_cursor, UNW_REG_SP, &sp);
return sp;
}
// a little helper for absolute delta of unsigned integers
#include <algorithm>
template<class UI>
UI abs_udelta(UI left, UI right) {
return max(left,right) - min(left,right);
}
unsigned long global_bottom;
rlim_t global_max;
// a test function to grow the call stack
int recurse(int index) {
if(index < 2 ) {
auto stack_size = abs_udelta(current_sp(), global_bottom);
cout << "Current stack size: " << stack_size
<< "\tStack left: " << global_max - stack_size << '\n';
return index;
}
return recurse(index - 1) + recurse(index - 2); // do the fibonacci
}
int main() {
global_max = get_max_stack_size();
global_bottom = bottom_of_stack();
auto appr_bottom = appr_bottom_of_stack();
cout << "Maximum stack size: "
<< global_max << '\n';
cout << "Approximate bottom of the stack by unwinding: "
<< (void*)appr_bottom << '\n';
if(global_bottom > 0) {
cout << "Bottom of the stack in /proc/<pid>/stat: "
<< (void*)global_bottom << '\n';
cout << "Approximation error: "
<< abs_udelta(global_bottom, appr_bottom) << '\n';
} else {
global_bottom = appr_bottom;
cout << "Could not parse /proc/<pid>/stat" << '\n';
}
// use the result so call won't get optimized out
cout << "Result of recursion: " << recurse(6);
}
Output:
Maximum stack size: 8388608
Approximate bottom of the stack by unwinding: 0x7fff64570af8
Bottom of the stack in /proc/<pid>/stat: 0x7fff64570b00
Approximation error: 8
Current stack size: 640 Stack left: 8387968
Current stack size: 640 Stack left: 8387968
Current stack size: 576 Stack left: 8388032
Current stack size: 576 Stack left: 8388032
Current stack size: 576 Stack left: 8388032
Current stack size: 576 Stack left: 8388032
Current stack size: 576 Stack left: 8388032
Current stack size: 512 Stack left: 8388096
Current stack size: 576 Stack left: 8388032
Current stack size: 576 Stack left: 8388032
Current stack size: 512 Stack left: 8388096
Current stack size: 512 Stack left: 8388096
Current stack size: 512 Stack left: 8388096
Result of recursion: 8