如何定义全局函数指针并分配给特定地址

Posted

技术标签:

【中文标题】如何定义全局函数指针并分配给特定地址【英文标题】:How to define a global func pointer and assign to a specific address 【发布时间】:2019-11-23 04:22:21 【问题描述】:

这对有经验的 C 程序员来说应该很明显,但对我来说不是。 我的情况:我有一个函数的常量地址。我想定义一个符号,分配给地址并能够像函数一样调用它。我希望这个函数在一个单独的头文件中,所以我可以在任何需要这个函数的地方包含它。

到目前为止我做了什么:

// utils.h
#pragma once

typedef int* (*funptr)();
const funptr get_game_obj2 = (funptr2)0x00401870;

此代码按预期工作。但。我试图找出如何在没有 typedef 的情况下达到同样的效果。 我尝试了类型和括号的不同组合,但没有任何效果。我有一种强烈的感觉,它应该是可行的,但找不到任何对谷歌的参考。

 const int* (*get_game_obj2)() = (int* (*)())0x00401870;
 (int* (*)()) get_game_obj2 = (int* (*)())0x00401870;
 int* (*)() get_game_obj2 = (int* (*)())0x00401870;
 const( int* (*get_game_obj2)()) = 0x00401870;

顺便说一句,之前我遇到了一个问题,工作代码编译了两次,我得到了重新定义编译错误。 fatal error LNK1169: one or more multiply defined symbols found 我认为这是因为我包含了来自多个源文件的头文件。我用const 关键字管理它。但令我困扰的是,在const 之前我尝试过#pragma once 和这样的包含守卫:

#pragma once
#ifndef GRANDPARENT_H
#define GRANDPARENT_H
  typedef int* (*funptr)();
  funptr get_game_obj2 = (funptr2)0x00401870;
#endif /* !GRANDPARENT_H */

我的期望是,有了这样的保护,这个文件应该只在编译期间执行一次,所以不应该发生重新定义。为什么这不起作用,但const 起作用了? 谢谢

【问题讨论】:

这与函数指针无关。如果该类型是简单的int,您将遇到多个定义的相同问题。输入extern 关键字。 1.你的场景对我来说有点奇怪,你确定你的函数所在的地址是固定的吗?这对我来说似乎很容易破碎。 2. 你为什么要避免使用 typedef,它似乎是你的情况的最佳选择,迄今为止最易读 【参考方案1】:

你是如此接近。

typedef 上的const 适用于其***类型,因为int *(*)() 是指向函数的指针,所以const funptr 得到int *(*const)(),一个指向函数的常量指针。

int *(*const get_game_obj2)() = (int *(*)())0x401870;

编辑:

我包含来自多个源文件的头文件。我用 const 关键字管理它。但困扰我的是一个事实,在 const 之前我尝试过一次#pragma 和一个包含保护

源文件是分开编译的,如果你在一个头文件中定义对象,在多个源文件中包含那个头文件,然后全部编译,你会在每个编译文件中得到这些对象的定义。尝试将它们链接在一起会导致来自任何链接器的多定义错误。

对于像这样简单的常量,你可能会侥幸逃脱

#define get_game_obj2 ((int *(*)())0x401870)

只需声明内联转换。

这种代码作为一种学习工具很有趣,如果您正在编写微控制器代码,其中每一点都很宝贵,但工作量、复杂性和脆弱性是真正的开销,这种代码很有用。你不对他们负责,但是无论你对这个代码负责的人都应该有具体的,而不是抽象的,不是手摇的,具体的,这样做的理由。就像“如果我们不这样做,我们会冒代码不适合 eeprom 的风险”或“如果我们不这样做,你永远不会绕着 C 类型的语法”。

【讨论】:

非常感谢!它有效,更重要的是,现在我对这段代码中发生的事情有了更好的理解。我仍然不明白为什么const 解决了这个问题,但是为了在没有 const 的情况下完成它,我可以在带有修饰符extern 的头文件中声明我的变量并在单独的源文件中定义(分配给地址)。但是在这种方法的任何变体中,我最终都会得到一个包含函数地址的变量。并使用这个变量作为函数指针,我可以使用该函数。对吗? 我喜欢#define 方法的一点是,我什至不将该地址存储在任何地方,我只是在原地使用该地址并由 C 编译器完成类型检查。这是我最初的设想,我想怎么做。我对另外 4 个字节并不贪心,但这毫无意义。我认为这就是我的情况。 链接器如何处理 const 对象的多个相同定义有点武断,我不再记得 C 是否需要诊断,甚至可能允许这样做。 ... 但 C++ 确实 允许这样做,完全绕过了任意性。没有显式标记 extern 的 const 对象定义根本没有全局链接,该定义对于定义文件是本地的。但是你问的是 C,一点点挖掘提醒我将它们视为外部,并没有标记任何类型的链接器合并。 ... 所以对于 C++ 编译器,您最终会得到一个包含函数地址的文件范围 const 变量,但编译器很可能会将其折叠为文字,因为 C++ 是围绕消除抽象而构建的像这样的处罚。 C 编译器将有一个带有函数地址的全局范围变量,我忘记了是否允许假定 const 在任何地方都受到尊重,这对我来说似乎很不确定。

以上是关于如何定义全局函数指针并分配给特定地址的主要内容,如果未能解决你的问题,请参考以下文章

如何在 STL 中使用指向向量的指针,就像我们在将数组地址传递给另一个函数时将指针分配给数组一样?

C语言如何给指针分配内存?

Delphi 中 如何将函数的地址赋值给指针变量?

以下语句是不是将物理地址或虚拟地址分配给指针?

函数指针与指针函数

C的函数指针与指针函数