【问题标题】:Where exactly do function pointers point?函数指针到底指向哪里?
【发布时间】:2010-10-10 11:36:37
【问题描述】:

鉴于所有原始数据类型和对象都分配了内存,很容易直观地想象指向这些类型的指针。

但是函数指针到底指向哪里呢?既然指令被转换成机器码并驻留在内存中,我们是否应该认为它们指向对应于函数指令开始的内存位置?

由于非法内存访问,我们面临许多指针错误。当函数指针指向数据内存而不是指令内存时,是否会发生错误?

【问题讨论】:

  • 您是否在函数指针或其他指针上看到非法内存访问?
  • “由于非法内存访问,我们面临许多指针错误”是什么意思?这些错误是如何发生的?这些错误是什么?
  • @Steve No @S.Lott 我指的是当我们将 int * 初始化为一些受保护的内存地址的垃圾时出现的错误。
  • 无论支持者怎么说,@KeithThompson 的回答是迄今为止最完整/最准确的。

标签: c++ c pointers function-pointers


【解决方案1】:

函数指针也指向内存,唯一的区别是该内存位置有可执行代码而不是数据。

在许多平台上,如果您尝试执行数据(例如常规内存),您会崩溃或导致异常。这称为数据执行保护 - 一种安全措施,可防止应用程序无意中运行可能被恶意软件放置在那里的可疑代码。

【讨论】:

  • 而且我认为在开始执行之前,相关的功能框架已被初始化。例如,调用创建的特定操作数堆栈和局部变量数组(带有传递的参数)。
【解决方案2】:

函数指针包含函数的地址——无论它对给定系统意味着什么。您可以使用它来间接调用函数,您可以分配和比较函数指针值。您还可以将函数指针转换为另一种指向函数的指针类型,等等。

编译器实现函数指针的最直接方式是作为函数的内存地址,大多数编译器都是这样做的,但语言标准没有指定。一些系统(我认为 IBM 的 AS/400 就是一个例子)将附加信息存储在函数指针中。只要正确实现所需的语义,编译器就可以将函数指针作为整数索引实现到描述符表中。

无法取消引用函数指针。函数调用需要一个指针,而不是函数名,作为它的前缀表达式;如果您使用函数名称,则该名称将隐式转换为指针(就语言而言;生成的机器代码可能不同)。所以程序没有可移植的方法来检测函数指针是否实际包含内存地址。

不可移植,给定函数func,您可以执行以下操作:

printf("Address of func is %p\n", (void*)func);

你会可能看到一些看起来像人类可读的内存地址表示的东西。但严格来说,函数指针到void*的转换行为不是由语言定义的,在某些系统上可能不起作用。

可能甚至可以将函数指针转换为unsigned char* 并检查函数的机器代码,但远远超出了 C 标准定义的任何内容。

最好将函数指针视为以某种未指定方式引用特定函数的不透明值。

【讨论】:

    【解决方案3】:

    这是一个代码指针。它指向函数的地址。基本上和你描述的一样。是的,如果你的指针没有指向你所期望的,你就会遇到问题。

    【讨论】:

      【解决方案4】:

      函数指针指向内存中的address of the function

      根据通常分配函数指针的方式,如果您让它们指向数据位置,我会感到惊讶。它们通常不会被强制转换,因此不太可能指向除有效函数之外的任何地方。如果你经常铸造它们,那么这可能是一个问题。但更有可能是您传递给函数的数据是错误的。

      【讨论】:

        【解决方案5】:

        好吧,我不确定,但考虑到函数是指令(ADD、SUB、JMP)并且它们每个都有十六进制值,我相信您不会更改函数,而只会更改 JMP 指令().. .

        【讨论】:

        • 如果您要更改 JMP 指令,您有自修改代码,这通常被认为是黑魔法。函数指针就像其他指针一样——存储在 RAM 中的地址; JMP 从变量而不是编译到程序中的数据中获取它的目标。
        • 我认为有些 CPU 以这种方式处理所有指针,通过将“指针”作为代码中的值,例如非常简单的 PIC 和 DSP。
        • 我不明白,我的思路缺陷在哪里?
        • Diones,缺陷是函数指针通常不是通过重写 JMP 指令来实现的。这仅在非常 非常 小 CPU 上完成。通常 CPU 使用某种形式的间接分支指令。
        • 编译器不一定会创建自修改代码来实现函数指针,尽管在某些情况下它可能会这样做。例如,在 Windows/IA-32 上,您可以使用 VirtualAlloc 和 PAGE_EXECUTE_READWRITE 标志分配内存,并将字节码写入该地址并调用它...
        猜你喜欢
        • 2016-07-12
        • 2012-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-26
        • 1970-01-01
        相关资源
        最近更新 更多