我想在同一个成员函数中获取成员函数的地址。已经获取了这个指针,所以我知道从哪个对象调用。当然编译器抱怨我正在尝试使用指向此函数的指针而不调用它。我看到将这个规则放在一个对象之外的重点。有没有办法让“我自己”(函数在被调用时解决)地址?
这仅用于调试目的,应该在宏中使用。有办法做到这一点真是太好了。
澄清的代码:
class A
{
void do_stuff()
{
printf("0x%X\n", (void*)(this->do_stuff));
}
};
这是在嵌入式系统上我不明白为什么绝对没有办法获得do_stuff在flash中保存的地址。
编辑我尝试获取“指向成员函数的指针”,如下所示:
printf("CAPP::TASK 0x%08X\n", &CApp::Start);
它给了我0x08013E85,我在链接器映射中查找它,它正是我正在寻找的功能。这是使用KeilμVision5作为编译器的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%08X\n", a);
...
}
令人讨厌的黑客攻击,但它确实奏效了。但为什么这有效呢?可悲的是,我没有__va_arg(...)的实现。 __va_arg如何对给定类型进行类型转换?有没有办法以某种方式使用该功能?
答案 0 :(得分:3)
指向成员的指针函数通常是普通指针大小的两倍,如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
hack是有效的,因为你的编译器将指向成员函数的指针&CApp::Start
表示为双字对象,其中一个单词中的函数地址为你通过varargs hack阅读,因为两个单词被推入堆栈然后你只读了其中一个。您可以使用union获得类似的结果:
union dirty_hack
{
void (CApp::*pmf)();
uint32_t words[2];
};
dirty_hack x;
x.pmf = &CApp::Start;
printf("Adr: 0x%08X\n", 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%08X\n", getaddr(&CApp::Start));
N.B。最好使用uintptr_t
而不是int32_t
来实现指针不是32位的系统的可移植性,尽管这种hackery本质上是不可移植的(上面的联合技巧依赖于类型惩罚,这是未定义的行为,但有些编译器支持。)
答案 1 :(得分:2)
没有“这个对象的成员函数”这样的东西。成员函数由同一个类的所有对象有效地共享 - 它只是代码而不是数据。 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中引入),它包含一些特定于编译器的函数名称形式。