简体   繁体   English

在成员函数内部获取成员函数的地址

[英]Getting address to a member function inside the member function

I would like to get the address of a member function inside the same member function. 我想在同一成员函数内获取成员函数的地址。 The this pointer is acquired already so I know which object I am called from. 该指针已经被获取,因此我知道从哪个对象调用。 Of course the compiler complains that I'm trying to use a pointer to this function while not calling it. 当然,编译器会抱怨我试图在不调用该函数的情况下使用指向该函数的指针。 I see the point for having this rule outside an object. 我知道在对象之外具有此规则的意义。 Is there no way to get "MY OWN" (the functions address when it is called) address? 没有办法获取“ MY OWN”(调用时的函数地址)地址吗?

This is only for debugging purposes and should be used in a macro. 这仅用于调试目的,应在宏中使用。 It would be great to have a way to do this. 有一种方法可以做到这一点。

Code to clarify: 代码说明:

class A
{
    void do_stuff()
    {
        printf("0x%X\n", (void*)(this->do_stuff));
    }
};

This is on an embedded system I do not get why there is absolutely no way to get the address where do_stuff is saved in flash. 这是在嵌入式系统上,我不明白为什么绝对没有办法获取do_stuff保存在闪存中的地址。

Edit I tried getting the "pointer to member function" like this: 编辑我试图像这样获取“指向成员函数的指针”:

printf("CAPP::TASK 0x%08X\n", &CApp::Start);

It gives me 0x08013E85 which I look up in my linker map and it is exactly the function I am looking for. 它给了我0x08013E85,可以在链接器图中查找它,而这正是我要查找的功能。 This is mdk-arm using Keil µVision 5 as a compiler. 这是使用Keil µVision 5作为编译器的mdk-arm。 Is this correct? 这个对吗?

Edit 2: All kinds of type casts give me invalid type conversion. 编辑2:各种类型强制转换会给我带来无效的类型转换。 Although printf's output is correct: Printf uses variadic macros. 尽管printf的输出是正确的:Printf使用可变参数宏。 Let's rebuild that: 让我们重建一下:

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);
    ...
}

Nasty hack, but it worked. 令人讨厌的骇客,但行得通。 But why does this work? 但是为什么这样做呢? Sadly I don't have the implementation of __va_arg(...). 可悲的是我没有__va_arg(...)的实现。 How does __va_arg typecast values to the given type? __va_arg如何将值转换为给定类型? Is there a way to use that feature somehow? 有办法以某种方式使用该功能吗?

A pointer-to-member function is generally twice the size of a normal pointer like a void* so there is no direct conversion possible in standard C++. 指针到成员函数通常是普通指针(如void*大小的两倍,因此在标准C ++中无法进行直接转换。

https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html documents a GCC extension which allows you to get a normal (non-member) function pointer by combining this and &CApp::Start (that page also explains why a pointer to member function has additional info beyond just the function address). https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html记录了一个GCC扩展名,该扩展名允许您通过this&CApp::Start (该页面)结合使用来获得常规(非成员)功能指针还说明了为什么指向成员函数的指针除了函数地址之外还具有其他信息)。

That extension could be used like so: 该扩展名可以像这样使用:

typedef void (*pf_type)(CApp*);
pf_type pf = (pf_type)&CApp::Start;

I would guess that your hack with va_arg works because your compiler represents the pointer-to-member-function &CApp::Start as a double-word object, with the function address in one of the words, which you read via the varargs hack because two words get pushed onto the stack and then you only read one of them. 我猜您使用va_arg黑客攻击是va_arg因为您的编译器将指向成员函数&CApp::Start的指针表示为双字对象,函数地址为其中一个单词,您可以通过varargs hack读取该单词,因为两个单词被压入堆栈,然后您只读其中一个。 You might be able to get similar results using a 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

You can generalise that using a template: 您可以使用模板进行概括:

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));

NB it would be better to use uintptr_t not int32_t for portability to systems where pointers are not 32-bits, although this sort of hackery is inherently non-portable (the union trick above relies on type-punning, which is undefined behaviour but supported by some compilers). 注意:最好使用uintptr_t而不是int32_t来将其移植到指针不是32位的系统,尽管这种黑客本来是不可移植的(上面的联合技巧依赖于类型绑定,这是未定义的行为,但受支持)一些编译器)。

There is no such thing as "this object's member function." 没有“该对象的成员函数”之类的东西。 The member functions are effectively shared by all objects of the same class - it's just code, not data. 成员函数有效地由同一类的所有对象共享 -仅仅是代码,而不是数据。 this is usually passed as an extra hidden parameter to these functions. this通常是作为一个额外的隐藏参数,这些功能通过。

In effect, the compiler transforms this: 实际上,编译器将其转换为:

struct Obj
{
  int a;

  int foo(int x) const { return x * a; }
};

int bar(const Obj &o)
{ return o.foo(42); }

into something like this: 变成这样的东西:

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); }

As you can see, there's no such thing as " &(o.foo) ". 如您所见,没有诸如“ &(o.foo) ”之类的东西。 All instances of obj have the same foo . obj所有实例都具有相同的foo

In addition, C++ does not give you access to this "staticised foo ", precisely because it's an implementation detail and compilers could do it differently if they so choose (or if the platform dictates it). 另外,C ++不允许您访问此“静态化的foo ”,这恰恰是因为它是一个实现细节,如果编译器选择(或由平台指定),则编译器可以以不同的方式进行操作。 The best you can get is the pointer-to-member to the function, &Obj::foo . 最好的获得指向函数&Obj::foo的成员的指针。 Of course, this is not a real address, it's more like an offset within the class Obj . 当然,这不是真实地址,更像是Obj类中的偏移量。 And you need to spell out its name explicitly - there's no way to refer to "the enclosing function" without using its name. 而且您需要明确拼写其名称-如果不使用其名称,就无法引用“封闭函数”。

The best you can get without naming the function is the predefined variable __func__ (introduced in C++11), which contains some compiler-specific form of the function's name. 在不命名函数的情况下,最好的选择是预定义的变量__func__ (在C ++ 11中引入),该变量包含一些特定于编译器的函数名称形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM