15
void demo()
{
    printf("demo");
}

int main()
{
    printf("%p",(void*)demo);
    return 0;
}

The above code prints the address of function demo.
So if we can print the address of a function, that means that this function is present in the memory and is occupying some space in it.
So how much space it is occupying in the memory?

kevin gomes
  • 1,775
  • 5
  • 22
  • 30

7 Answers7

19

You can see for yourself using objdump -r -d:

0000000000000000 <demo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   bf 00 00 00 00          mov    $0x0,%edi
                        5: R_X86_64_32  .rodata
   9:   b8 00 00 00 00          mov    $0x0,%eax
   e:   e8 00 00 00 00          callq  13 <demo+0x13>
                        f: R_X86_64_PC32        printf-0x4
  13:   5d                      pop    %rbp
  14:   c3                      retq   

0000000000000015 <main>:

EDIT

I took your code and compiled (but not linked!) it. Using objdump you can see the actual way the compiler lays out the code to be run. At the end of the day there is no such thing as a function: for the CPU it's just a jump to some location (that in this listing happens to be labeled). So the size of the "function" is the size of the code that comprises it.


There seems to be some confusion that this is somehow not "real code". Here is what GDB says:

Dump of assembler code for function demo:
   0x000000000040052d <+0>:     push   %rbp
   0x000000000040052e <+1>:     mov    %rsp,%rbp
   0x0000000000400531 <+4>:     mov    $0x400614,%edi
   0x0000000000400536 <+9>:     mov    $0x0,%eax
   0x000000000040053b <+14>:    callq  0x400410 <printf@plt>
   0x0000000000400540 <+19>:    pop    %rbp
   0x0000000000400541 <+20>:    retq   

This is exactly the same code, with exactly the same size, patched by the linker to use real addresses. gdb prints offsets in decimal while objdump uses the more favourable hex. As you can see, in both cases the size is 21 bytes.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • 2
    some explanation would be helpful – embert Feb 12 '14 at 17:42
  • @embert: Those are the machine instructions generated by the compiler for your function demo. What you see on the screen is not what lives in memory, but the numerical representations of those instructions does. – Linuxios Feb 12 '14 at 17:44
  • The output of objdump has nothing to do with how the program is stored in ram memory. – José Tomás Tocino Feb 12 '14 at 17:44
  • 1
    @JoséTomásTocino: Not completely true. Those are the textual representations of the instructions that are going to be loaded into RAM. – Linuxios Feb 12 '14 at 17:44
  • @JoséTomásTocino Please expand on that, I am very interested. – cnicutar Feb 12 '14 at 17:46
  • @Linuxios I think you can also see the offsets (the numbers on the right) so you can rightfully infer the size of the code from them. – cnicutar Feb 12 '14 at 17:50
  • @cnicutar: Actually, I think that the hex data on the right is the binary representation, which means that this function is 21 bytes long (I think). – Linuxios Feb 12 '14 at 17:50
  • objdump is merely the representation of the generated code, but depending on the platform the instructions may be laid out in memory differently. – José Tomás Tocino Feb 12 '14 at 17:50
  • 1
    @JoséTomásTocino: How do you mean? The binary on the right is the binary representation of the machine code for this architecture. Of course it will be different for another arch, but on the one objdump was run on (guessing x86 or x64), it should be the same. – Linuxios Feb 12 '14 at 17:53
  • @JoséTomásTocino I added a `gdb` dump to address your concerns. – cnicutar Feb 12 '14 at 17:57
  • For `.o` files you should always use the `-r` option to `objdump` in addition to `-d`. It will show relocations, so you can see where the linker will patch addresses in, rather than just seeing confusing wrong/zero addresses all over the place. – R.. GitHub STOP HELPING ICE Feb 12 '14 at 18:00
  • @R.. For me `00 00 00..` always scream "relocate" but you are of course right. Edited. – cnicutar Feb 12 '14 at 18:02
  • On x86_64 it's 0 because it uses RELA relocations where the addend is stored in the relocation table. On other systems that use REL relocations, the addend is stored at the address where the relocation is to take place, so you have random nonzero constants that are actually offsets/addends to the relocation appearing. – R.. GitHub STOP HELPING ICE Feb 12 '14 at 20:39
12

So if we can print the address of a function, that means that this function is present in the memory and is occupying some space in it.

Yes, the functions you write are compiled into code that's stored in memory. (In the case of an interpreted language, the code itself is kept in memory and executed by an interpreter.)

So how much space it is occupying in the memory?

The amount of memory depends entirely on the function. You can write a very long function or a very short one. The long one will require more memory. Space used for code generally isn't something you need to worry about, though, unless you're working in an environment with severe memory constraints, such as on a very small embedded system. On desktop computer (or even mobile device) with a modern operating system, the virtual memory system will take care of moving pages of code into or out of physical memory as they're needed, so there's very little chance that your code will consume too much memory.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • What about an empty function. It is also having an address. So it is occupying some space also. If yes, then what in the function is occupying that memory? – kevin gomes Feb 12 '14 at 17:51
  • 1
    @kevingomes: An empty function will most likely be optimized away by the compiler. If not, it will consist of function setup and teardown operations. – Linuxios Feb 12 '14 at 17:52
  • @Linuxios :`An empty function will most likely be optimized away by the compiler`..... means??? – kevin gomes Feb 12 '14 at 17:55
  • @kevingomes: That if the compiler sees a function that does absolutely nothing, most likely, that function won't even be in the generated machine code. The compiler won't even compile it. – Linuxios Feb 12 '14 at 17:55
  • @Linuxios : if such is a case then it should not occupy memory space. – kevin gomes Feb 12 '14 at 17:57
  • @Linuxios : but I am able to print its address – kevin gomes Feb 12 '14 at 17:58
  • 6
    @kevingomes: By referencing the function with a function pointer the compiler becomes unable to optimize the function away and must include a function that just sets up and tears down in the final code. By referencing the function you force the compiler to include it. – Linuxios Feb 12 '14 at 17:59
  • 7
    "Sets up and tears down" is misleading. A good compiler will compile an empty function with `void` return type to a single `ret` instruction (or similar). – R.. GitHub STOP HELPING ICE Feb 12 '14 at 18:01
  • 1
    The minimum possible size of a function depends on the architecture, but is usually one or two machine instructions. Wackier cases include SPARC, which has a delay slot on its return instruction, and Itanic, whose pseudo-VLIW nature means that you can't have fewer than three machine instructions in a "bundle", although two of them can be NOPs. Also, the ABI may mandate that all function entry addresses are aligned to some multiple of the instruction size, which effectively increases the minimum space occupied by any one function. – zwol Feb 12 '14 at 18:04
  • 2
    `(In the case of an interpreted language, the code itself is kept in memory and executed by an interpreter.)` This is not strictly true, most modern languages compile to **some** sort of lower level bytecode instead of storing text or the AST in memory. – TC1 Feb 12 '14 at 20:28
5

Of course it's occupying space in memory, the entire program is loaded in memory once you execute it. Typically, the program instructions are stored in the lowest bytes of the memory space, known as the text section. You can read more about that here: http://www.geeksforgeeks.org/memory-layout-of-c-program/

José Tomás Tocino
  • 9,873
  • 5
  • 44
  • 78
  • The program must be loaded in some form of memory, but not necessarily RAM. Many microcontrollers have a program store which is implemented in flash or ROM. – supercat Feb 12 '14 at 22:35
3

Yes, all functions that you use in your code do occupy memory space. However, the memory space does not necessarily belong exclusively to your function. For example, an inline function would occupy space inside each function from where it is called.

The standard does not provide a way to tell how much space a function occupies in memory, as pointer arithmetic, the trick that lets you compute sizes of contiguous memory regions in the data memory, is not defined for function pointers. Moreover, ISO C forbids conversion of function pointer to object pointer type, so you cannot get around this restriction by casting your function pointer to, say, a char*.

printf("%p",demo);

The above code prints the address of function demo().

That is undefined behavior: %p expects a void*, while you are passing it a void (*)(). You should see a compiler warning, telling that what you are doing is not valid (demo).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

As for determining the amount of memory it is occupying, this is not possible at run-time. However, there are other ways you can determine it: How to get the length of a function in bytes?

Community
  • 1
  • 1
turnt
  • 3,235
  • 5
  • 23
  • 39
2

The functions are compiled into machine code that will run only on a specific ISA (x86, probably ARM if it's going to run on your phone, etc.) Since different processors may need more or fewer instructions to run the same function, and the length of instructions can also vary, there is no way to know in advance exactly how big the function will be until you compile it.

Even if you know what processor and operating system it will be compiled for, different compilers will create different, equivalent representations of the function depending on which instructions they use and how they optimize the code.

Also, keep in mind a function occupies memory in different ways. I think you are talking about the code itself, which is its own section. During execution, the function can also occupy space on the stack - every time the function is called, more memory is taken up in the form of a stack frame. The amount depends on the number and type of local variables and arguments declared by the function.

GVH
  • 416
  • 3
  • 16
  • Functions are definitely *not* stored on the stack. -1. – Linuxios Feb 12 '14 at 17:45
  • @Linuxios but first two paras are good, GVH should remove last para – Grijesh Chauhan Feb 12 '14 at 17:46
  • My mistake - thanks for the correction, I'll read up on this and set myself straight. – GVH Feb 12 '14 at 17:48
  • @GVH: If you make another edit I will remove the downvote. You were close -- the function's stack frame, locals, arguments, and return value are on the stack. – Linuxios Feb 12 '14 at 17:51
  • @GrijeshChauhan : What about an empty function. It is also having an address. So it is occupying some space also. If yes, then what in the function is occupying that memory as it is empty? – kevin gomes Feb 12 '14 at 17:52
  • 2
    @kevingomes Yes empty function occupies space if not optimized and remove by compilers. `what in the function is occupying that memory as it is empty?` just a return. Just follow @ cnicutar's approach to explore further. But remember you would explore machine and compiler 's specific behaviour That may be unspecified in language standard. – Grijesh Chauhan Feb 12 '14 at 17:54
  • @Linuxios I think it's accurate now. – GVH Feb 12 '14 at 18:11
2

Yes however you can declare it as being inline, so the compiler will take the source code and move it where ever you call that function. Or you can also use preprocessor macros. Though do keep in mind using inline will generate larger code but it will execute faster, and the compiler can decide to ignore your inline request if it feels that it will become to large.