8

我正在学习函数指针,我知道我们可以使用函数指针来指向函数。然后我假设它们留在内存中。它们是留在堆栈还是堆?我们可以计算它们的大小吗?

4

9 回答 9

6

代码空间是由链接器在构建代码时静态分配的。在您的代码由操作系统加载的情况下,操作系统加载程序从操作系统请求该内存并将代码加载到其中。类似地,正如其名称所暗示的那样,此时分配了静态数据,初始堆栈也是如此(尽管如果创建了额外的线程,可能会创建更多堆栈)。

关于确定函数的大小,链接器知道此信息,并且在大多数工具链中,链接器可以创建一个映射文件,其中包括所有静态内存对象的大小和位置(即那些未在运行时实例化的对象)堆栈或堆上的时间)。

没有保证在运行时确定函数大小的方法(并且没有理由这样做)但是,如果您假设链接器在内存中按顺序定位源代码中相邻的函数,那么以下可能会给出函数大小的指示:

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++ 中试过这个,它只在“发布”版本中给出了有效的结果;“调试”构建的结果没有真正意义。我建议这个练习只是为了兴趣,没有实际用途。

观察代码大小的另一种方法当然是查看调试器中代码的反汇编。

于 2012-06-10T08:42:42.847 回答
3

函数是文本段的一部分(可能是也可能不是“堆”)或您使用的体系结构的等价物。编译后没有关于它们大小的数据,最多您可以从符号表中获取它们的入口点(不一定可用)。因此,在您将遇到的大多数 C 环境中,您无法在实践中计算它们的大小。

于 2012-06-10T06:49:26.080 回答
3

它们(通常)与堆栈或堆分开。

有很多方法可以找到它们的大小,但它们都不是便携式的。如果您认为您需要/想知道尺寸,那么您很有可能正在做一些您可能应该避免的事情。

于 2012-06-10T06:50:13.467 回答
1

为简单起见,函数通常不会进入堆栈或堆,因为它们是只读数据,而堆栈和堆是读写存储器。

你真的需要在运行时知道它的大小吗?如果不是,您可以通过简单的方式获得它,objdump -t -i .text a.out其中 a.out 是您的二进制文件的名称。这.text是链接器放置代码的地方,加载器可以选择将此内存设为只读(甚至只是只执行)。如果是的话,正如之前的帖子中已经回复的那样,有办法做到这一点,但它很棘手且不可移植...... Clifford给出了最直接的解决方案,但链接器很少将函数以这种顺序的方式放入final二进制。另一种解决方案是使用编译指示在链接器脚本中定义部分,并为全局变量保留一个存储空间,链接器将使用包含您的函数的 SIZEOF(...) 部分填充该全局变量。它依赖于链接器,并非所有链接器都提供此功能。

于 2012-06-10T17:13:31.477 回答
1

如上所述,函数大小由编译器在编译时生成,所有大小在链接时对链接器都是已知的。如果你必须这样做,你可以让链接器踢出一个包含起始地址、大小,当然还有名字的映射文件。然后,您可以在代码中在运行时解析它。但我认为没有一种可移植的、可靠的方法可以在运行时计算它们而不超出 C 的范围。

linux 内核类似地使用它来进行运行时分析。

于 2012-06-11T05:10:27.117 回答
1

有一种有趣的方法可以发现函数的大小。

#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],并返回函数的大小。

于 2020-04-08T13:12:36.300 回答
0

C 没有垃圾收集器。有一个指向某物的指针不会让它留在内存中。

函数始终在内存中,无论您是否使用它们,无论您是否保留指向它们的指针。

动态分配的内存可以被释放,但它与保持指向它的指针无关。您不应该保留指向已释放内存的指针,并且应该在丢失指向它的指针之前释放它,但是语言不会自动执行此操作。

于 2012-06-10T07:01:38.310 回答
0

如果有类似函数大小的东西,它应该是它的堆栈帧大小。或者更好的是,请尝试考虑一下,根据您的说法,函数的大小应该是多少?你的意思是它的静态大小,即它加载到内存中时所有操作码的大小?如果这是你的意思,那么我看不出他们有任何语言提供的功能来找出它。也许你在寻找一些hack。可以有很多。但我还没有尝试过。

于 2012-06-10T09:59:22.090 回答
0
#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;
}

希望您能得到答案,所有功能都存储在某个地方

这里是代码的输出

以上代码的输出

于 2019-09-12T06:24:25.463 回答