我正在学习函数指针,我知道我们可以使用函数指针来指向函数。然后我假设它们留在内存中。它们是留在堆栈还是堆?我们可以计算它们的大小吗?
9 回答
代码空间是由链接器在构建代码时静态分配的。在您的代码由操作系统加载的情况下,操作系统加载程序从操作系统请求该内存并将代码加载到其中。类似地,正如其名称所暗示的那样,此时分配了静态数据,初始堆栈也是如此(尽管如果创建了额外的线程,可能会创建更多堆栈)。
关于确定函数的大小,链接器知道此信息,并且在大多数工具链中,链接器可以创建一个映射文件,其中包括所有静态内存对象的大小和位置(即那些未在运行时实例化的对象)堆栈或堆上的时间)。
没有保证在运行时确定函数大小的方法(并且没有理由这样做)但是,如果您假设链接器在内存中按顺序定位源代码中相邻的函数,那么以下可能会给出函数大小的指示:
int first_function()
{
...
}
void second_function( int arg )
{
...
}
int main( void )
{
int first_function_length = (int)second_function - (int)first_function ;
int second_function_length = (int)main - (int)second_function ;
}
然而YMMV;我在 VC++ 中试过这个,它只在“发布”版本中给出了有效的结果;“调试”构建的结果没有真正意义。我建议这个练习只是为了兴趣,没有实际用途。
观察代码大小的另一种方法当然是查看调试器中代码的反汇编。
函数是文本段的一部分(可能是也可能不是“堆”)或您使用的体系结构的等价物。编译后没有关于它们大小的数据,最多您可以从符号表中获取它们的入口点(不一定可用)。因此,在您将遇到的大多数 C 环境中,您无法在实践中计算它们的大小。
它们(通常)与堆栈或堆分开。
有很多方法可以找到它们的大小,但它们都不是便携式的。如果您认为您需要/想知道尺寸,那么您很有可能正在做一些您可能应该避免的事情。
为简单起见,函数通常不会进入堆栈或堆,因为它们是只读数据,而堆栈和堆是读写存储器。
你真的需要在运行时知道它的大小吗?如果不是,您可以通过简单的方式获得它,objdump -t -i .text a.out
其中 a.out 是您的二进制文件的名称。这.text
是链接器放置代码的地方,加载器可以选择将此内存设为只读(甚至只是只执行)。如果是的话,正如之前的帖子中已经回复的那样,有办法做到这一点,但它很棘手且不可移植...... Clifford给出了最直接的解决方案,但链接器很少将函数以这种顺序的方式放入final二进制。另一种解决方案是使用编译指示在链接器脚本中定义部分,并为全局变量保留一个存储空间,链接器将使用包含您的函数的 SIZEOF(...) 部分填充该全局变量。它依赖于链接器,并非所有链接器都提供此功能。
如上所述,函数大小由编译器在编译时生成,所有大小在链接时对链接器都是已知的。如果你必须这样做,你可以让链接器踢出一个包含起始地址、大小,当然还有名字的映射文件。然后,您可以在代码中在运行时解析它。但我认为没有一种可移植的、可靠的方法可以在运行时计算它们而不超出 C 的范围。
linux 内核类似地使用它来进行运行时分析。
有一种有趣的方法可以发现函数的大小。
#define RETN_empty 0xc3
#define RETN_var 0xc2
typedef unsigned char BYTE;
size_t FunctionSize(void* Func_addr) {
BYTE* Addr = (BYTE*)Func_addr;
size_t function_sz = 0;
size_t instructions_qt = 0;
while(*Addr != (BYTE)RETN_empty && *Addr != (BYTE)RETN_var) {
size_t inst_sz = InstructionLength((BYTE*)Addr);
function_sz += inst_sz;
Addr += inst_sz;
++instructions_qt;
}
return function_sz + 1;
}
但是您需要一个返回指令大小的函数。您可以在此处找到查找指令长度的函数:获取汇编指令的大小。这个函数基本上一直检查函数的指令,直到找到要返回的指令(RETN)[0xc3,0xc2],并返回函数的大小。
C 没有垃圾收集器。有一个指向某物的指针不会让它留在内存中。
函数始终在内存中,无论您是否使用它们,无论您是否保留指向它们的指针。
动态分配的内存可以被释放,但它与保持指向它的指针无关。您不应该保留指向已释放内存的指针,并且应该在丢失指向它的指针之前释放它,但是语言不会自动执行此操作。
如果有类似函数大小的东西,它应该是它的堆栈帧大小。或者更好的是,请尝试考虑一下,根据您的说法,函数的大小应该是多少?你的意思是它的静态大小,即它加载到内存中时所有操作码的大小?如果这是你的意思,那么我看不出他们有任何语言提供的功能来找出它。也许你在寻找一些hack。可以有很多。但我还没有尝试过。
#include<stdio.h>
int main(){
void demo();
int demo2();
void (*fun)();
fun = demo;
fun();
printf("\n%lu", sizeof(demo));
printf("\n%lu", sizeof(*fun));
printf("\n%lu", sizeof(fun));
printf("\n%lu", sizeof(demo2));
return 0;
}
void demo(){
printf("tired");
}
int demo2(){
printf("int type funciton\n");
return 1;
}
希望您能得到答案,所有功能都存储在某个地方
这里是代码的输出