The implementation of a function sum in “C” is as follows:
int sum(int b[], int c)
{
int s,i;
if (c<0)
{
printf("ERROR\n");
}
s = 0;
for(i=0; i<c; ++i)
{
s = s + b[i];
}
return s;
}
I'd like to know, How much stack and heap in bytes is required by the function sum in X86 Linux platform? How to know this?
Is invocation of the function from within an interrupt-handler likely to be problematic or successful?
To build upon what other users have already pointed out, I will try to address both questions of the OP.
OP's first Question:
We can break this first question down into 2 parts. One is about stack size and the other is about heap size.
Stack Size:
To find out how much stack your function is using, you can use one of the GCC diagnostic pragmas, i.e. the
-Wframe-larger-than=<X>
pragma. Here is an example, on how to use it. First we add the pragma to the code and save the file.main.cpp
We can now try to compile the code:
which reports a size of 32 bytes.
stack-usage
compiler flag in GCC. So, we remove or comment out the// #pragma GCC diagnostic error "-Wframe-larger-than=1"
line and try to compile the file again, as shown below.junglefox@ubuntu:~$ gcc -c main.cpp -fstack-usage
This will generate a file
main.su
.which shows that apparently, we are using 48 bytes of stack.
Heap Size
To find out how much heap size our program is using, we will use the
valgrind
toolMassif
. For that we first need to add a main() function to our code (without which we cannot create a binary. And a binary is what we would need to be run with valgrind). So themain.cpp
, looks like this now,And now we will compile, build and run the binary with the help of valgrind, as shown here:
This will generate a bunch of info, which looks something like below:
which reports a total heap usage of 0 Kilobytes.
Also, as @mevets has tried to explain, you can always look into the the underlying assembly code generated by the compiler. In GCC, you could do,
which will show you what your function looks like in the underlying assembly output.
NOTE/EDIT: But just to be complete, in C or C++, without dynamic memory allocation using
malloc()
ornew
, you as a programmer are NOT using the heap. Also, unless you are declaring an array inside your function, you are not using any significant amount of the stack.OP's second Question:
As many people have kindly pointed out in the comments, do NOT use
printf()
in your Interrupt handler.To quote from this link:
So, apart from
printf()
, one thing that could take a long time, is how big an array you are passing to that function, when used as anInterrupt Service Routine
. It has a complexity ofO(n)
. Ifc
is too big, your program would be halted for a relatively long time till the ISR finishes going through thatfor()
loop.How much stack? After removing the printf, 0 bytes of stack are needed; the function is simple enough to work with 3 registers:
You need to be able to rely on a compiler to not do completely stupid stuff ( no matter what standard c## thinks ).
If you are so far into a corner that you need to count stack bytes, look for a mistake earlier in your path. Even Frank n Furter realized that solving the symptoms was different from the cause.
C has no concept of "stack"; and when code written in C is compiled you should think of it as being mangled into an unrecognizable form.
For example, if the caller does this:
Then the compiler can inline a completely separate copy of the
sum()
function, and then (using optimizations like constant folding, dead code elimination and loop unrolling) convert that separate copy of the function into (the equivalent of):..and then annotate it (or convert to "single static assignment' form) to allow more parallelism, like:
..and then convert into something like:
..and then optimize and reorder the instructions to get:
Notice that this looks nothing like the original code - e.g. there's no
printf()
, there's no loop and there's no branches.Of course (given that the function isn't
static
, and assuming no link time optimization or link time code generation is being done) the compiler will probably also generate an "I know nothing about the caller" version of the function and shove that into the output object file in case the linker wants it; and (if no other object files use the function) the linker might throw that version of the function away. In that case; you can look at the code the compiler generated for the "I know nothing about the caller" version, and then make worthless/incorrect assumptions based on the amount of stack used by code that is discarded and never executed.