功能占用内存空间吗?

时间:2014-02-12 17:38:33

标签: c function memory

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

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

上面的代码打印了函数demo的地址 因此,如果我们可以打印函数的地址,这意味着该函数存在于内存中并占用了一些空间。
那么它在内存中占据了多少空间?

7 个答案:

答案 0 :(得分:19)

您可以使用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>:

修改

我拿了你的代码并编译(但没有链接!)它。使用objdump,您可以看到编译器列出要运行的代码的实际方式。在一天结束时,没有一个功能:对于CPU而言,它只是跳转到某个位置(在此列表中恰好标记了)。所以“函数”的大小就是构成它的代码的大小。


似乎有些混淆,这在某种程度上不是“真正的代码”。这是GDB所说的:

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   

这是完全相同的代码,具有完全相同的大小,由链接器修补以使用实际地址。 gdb以十进制打印偏移,而objdump使用更有利的十六进制。如您所见,在这两种情况下,大小都是21个字节。

答案 1 :(得分:11)

  

因此,如果我们可以打印函数的地址,那就意味着这一点   函数存在于内存中并占据其中的一些空间。

是的,你编写的函数被编译成存储在内存中的代码。(在解释语言的情况下,代码本身保存在内存中并由解释器执行。)

  

那么它在内存中占用了多少空间?

内存量完全取决于功能。您可以编写很长的函数或非常短的函数。长的将需要更多的内存。用于代码的空间通常不是您需要担心的事情,除非您在具有严重内存限制的环境中工作,例如在非常小的嵌入式系统上。在具有现代操作系统的台式计算机(甚至移动设备)上,虚拟内存系统将根据需要将代码页移入或移出物理内存,因此代码消耗的可能性也很小。很多记忆。

答案 2 :(得分:5)

当然它占用了内存中的空间,整个程序在执行后会加载到内存中。通常,程序指令存储在存储空间的最低字节中,称为text section。您可以在此处详细了解:http://www.geeksforgeeks.org/memory-layout-of-c-program/

答案 3 :(得分:3)

是的,您在代码中使用的所有函数都会占用内存空间。但是,内存空间不一定只属于您的功能。例如,inline函数将占用每个函数内部的空间,从中调用它。

该标准没有提供一种方法来判断函数在内存中占用了多少空间,因为指针算法(即允许您计算数据存储器中连续内存区域大小的技巧)没有为函数指针定义。此外,ISO C禁止将函数指针转换为对象指针类型,因此您无法通过将函数指针转换为char*来解决此限制。

printf("%p",demo);
     

上面的代码打印了函数demo()的地址。

这是未定义的行为:%p期望void*,而您传递void (*)()。您应该看到编译器警告,告诉您正在执行的操作无效(demo)。

答案 4 :(得分:2)

至于确定它占用的内存量,这在运行时是不可能的。但是,您还可以通过其他方式确定它: How to get the length of a function in bytes?

答案 5 :(得分:2)

这些函数被编译成机器代码,只能在特定的ISA上运行(x86,如果它可能在手机上运行,​​可能是ARM等)。因为不同的处理器可能需要更多或更少的指令才能运行相同的函数,指令的长度也可以变化,在编译之前,没有办法事先知道函数的大小。

即使你知道它将被编译为什么处理器和操作系统,不同的编译器也会根据它们使用的指令以及它们如何优化代码来创建不同的等效函数表示。

另外,请记住一个函数以不同的方式占用内存。我想你在谈论代码本身,这是它自己的部分。在执行期间,该函数还可以占用堆栈上的空间 - 每次调用该函数时,都会以堆栈帧的形式占用更多内存。数量取决于函数声明的局部变量和参数的数量和类型。

答案 6 :(得分:2)

是的,但是你可以将它声明为内联,因此编译器将获取源代码并将其移动到调用该函数的位置。或者您也可以使用预处理器宏。虽然请记住使用内联将生成更大的代码但它会更快地执行,并且编译器可以决定忽略您的内联请求,如果它感觉它会变得很大。