正在获取成员函数内部成员函数的地址
Getting address to a member function inside the member function
我想获取同一成员函数内的成员函数的地址。this指针已经获取,所以我知道从哪个对象调用我。当然,编译器抱怨我试图在不调用该函数的情况下使用指向该函数的指针。我明白了在对象之外使用该规则的意义。难道没有办法获得"我自己"(调用时的函数地址)地址吗?
这仅用于调试目的,应在宏中使用。如果能有办法做到这一点,那就太好了。
澄清代码:
class A
{
void do_stuff()
{
printf("0x%Xn", (void*)(this->do_stuff));
}
};
这是在一个嵌入式系统上,我不明白为什么绝对没有办法获得do_stuff保存在flash中的地址。
编辑我试着得到这样的"指向成员函数的指针":
printf("CAPP::TASK 0x%08Xn", &CApp::Start);
它给了我0x08013E85,我在链接器映射中查找它,它正是我要查找的函数。这是使用KeilµVision 5作为编译器的mdk arm。这是正确的吗?
编辑2:所有类型转换都会导致类型转换无效。尽管printf的输出是正确的:printf使用可变宏。让我们重建一下:
uint32_t getAdr(uint32_t n, ...)
{
uint32_t adr=0;
va_list vl;
va_start(vl,n);
adr=va_arg(vl,uint32_t);
va_end(vl);
return adr;
}
#define GetAdr(x) getAdr(0,&x);
void CApp::Start()
{
uint32_t a = GetAdr(CApp::Start);
printf("Adr: 0x%08Xn", a);
...
}
讨厌的黑客,但它奏效了。但为什么这样做呢?遗憾的是,我没有__va_arg(…)的实现。__va_aorg如何将值类型转换为给定的类型?有没有办法以某种方式使用该功能?
指向成员函数的指针通常是像void*
这样的普通指针的两倍大,因此在标准C++中不可能进行直接转换。
https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html记录了一个GCC扩展,它允许您通过组合this
和&CApp::Start
来获得一个普通(非成员)函数指针(该页面还解释了为什么指向成员函数的指针除了函数地址之外还有其他信息)。
这个扩展可以这样使用:
typedef void (*pf_type)(CApp*);
pf_type pf = (pf_type)&CApp::Start;
我想你对va_arg
的破解之所以有效,是因为你的编译器将指向成员函数&CApp::Start
的指针表示为一个双字对象,函数地址在其中一个字中,你通过varargs破解读取,因为两个字被推到堆栈上,然后你只读取其中一个。使用联合,您可能会得到类似的结果
union dirty_hack
{
void (CApp::*pmf)();
uint32_t words[2];
};
dirty_hack x;
x.pmf = &CApp::Start;
printf("Adr: 0x%08Xn", x.words[0]); // might need to be x.words[1] instead
你可以使用一个模板来概括这一点:
template<typename F>
uint32_t
getaddr(F f)
{
union dirty_hack
{
F pmf;
uint32_t words[2];
};
dirty_hack x;
x.pmf = f;
return x.words[0]; // might need to be x.words[1] instead
}
printf("Adr: 0x%08Xn", getaddr(&CApp::Start));
注意:对于指针不是32位的系统,最好使用uintptr_t
而不是int32_t
来实现可移植性,尽管这种技巧本质上是不可移植的(上面的联合技巧依赖于类型双关,这是一种未定义的行为,但一些编译器支持)。
没有"这个对象的成员函数"这回事。成员函数被同一类的所有对象有效地共享-这只是代码,而不是数据。this
通常作为一个额外的隐藏参数传递给这些函数。
实际上,编译器会转换以下内容:
struct Obj
{
int a;
int foo(int x) const { return x * a; }
};
int bar(const Obj &o)
{ return o.foo(42); }
变成这样:
struct Obj
{
int a;
static int foo(const Obj *this, int x) { return this->x * a; }
};
int bar(const Obj &o)
{ return Obj::foo(&o, 42); }
正如你所看到的,根本不存在"&(o.foo)
"这样的东西。obj
的所有实例都具有相同的foo
。
此外,C++不允许您访问这个"静态foo
",正是因为它是一个实现细节,如果编译器愿意(或者平台要求),他们可以用不同的方式来实现。您能得到的最好的结果是指向函数&Obj::foo
的成员的指针。当然,这不是一个真实的地址,它更像是类Obj
中的一个偏移。您需要明确地拼写出它的名称——如果不使用它的名称,就无法引用"封闭函数"。
在不命名函数的情况下,最好的方法是预定义的变量__func__
(在C++11中引入),它包含一些编译器特定形式的函数名称。
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针