Вопрос по pointers, function-pointers, pointer-to-member, c++ – Как напечатать адрес функции-члена в C ++

13

Это выглядит какstd::cout не может напечатать адрес функции-члена, например:

#include <iostream>

using std::cout;
using std::endl;

class TestClass
{
  void MyFunc(void);

public:
  void PrintMyFuncAddress(void);
};

void TestClass::MyFunc(void)
{
  return;
}

void TestClass::PrintMyFuncAddress(void)
{
  printf("%p\n", &TestClass::MyFunc);
  cout << &TestClass::MyFunc << endl;
}

int main(void)
{
  TestClass a;

  a.PrintMyFuncAddress();

  return EXIT_SUCCESS;
}

результат примерно такой:

003111DB
1

Как я могу распечататьMyFuncадрес, используяstd::cout?

Ваш Ответ

4   ответа
16

что язык предоставляет какие-либо возможности для этого. Есть перегрузки дляoperator << для потоков, чтобы распечатать нормальноvoid* указатели, но указатели на функции-члены не могут быть преобразованы вvoid*s. Все это зависит от реализации, но обычно указатели на функции-члены реализуются в виде пары значений - флаг, указывающий, является ли функция-член виртуальной, и некоторые дополнительные данные. Если функция является не виртуальной функцией, эта дополнительная информация обычно является фактическим адресом функции-члена. Если функция представляет собой виртуальную функцию, эта дополнительная информация, вероятно, содержит данные о том, как выполнить индексирование в таблицу виртуальных функций, чтобы найти функцию, которую необходимо вызвать, для данного объекта-получателя.

В общем, я думаю, что это означает, что невозможно распечатать адреса функций-членов без вызова неопределенного поведения. Вам, вероятно, придется использовать какой-то специфический для компилятора прием для достижения этого эффекта.

Надеюсь это поможет!

Некоторые интересные статистические данные о размерах и реализациях функций указателей на элементы в различных компиляторах см. В таблице в нижней частиthis article, Однако, поскольку эта статья несколько устарела (написана в 2005 году), цифры, скорее всего, уже не точны, но дают приблизительное представление.
2

змер. А как насчет распечатки памяти указателя:

template<typename R, typename T, typename... Args>
std::string to_string(R (T::*func)(Args...))
{
    union PtrUnion
    {
        R(T::*f)(Args...);
        std::array<unsigned char, sizeof(func)> buf;
    };
    PtrUnion u;
    u.f = func;

    std::ostringstream os;

    os << std::hex << std::setfill('0');
    for (auto c : u.buf)
        os << std::setw(2) << (unsigned)c;

    return os.str();
}

Вы можете использовать это так:

class TestClass
{
    void foo();
};

...

std::cout << to_string(&TestClass::foo) << std::endl;
13

что причина, по которой вы получаете "1"; выводится вместо адреса, это то, что по какой-то причине компилятор приводит указатель вашей функции в логическое значение, так что вы действительно вызываетеostream& operator<< (bool val);

Похоже, это не связано с тем, что функция является функцией-членом.

Вы можете раскрыть такую информацию с помощью clang ++ -cc1 -ast-dump:

(ImplicitCastExpr 0x3861dc0 <col:13, col:25> '_Bool' <MemberPointerToBoolean>
    (UnaryOperator 0x3861940 <col:13, col:25> 'void (class TestClass::*)(void)' prefix '&'
        (DeclRefExpr 0x38618d0 <col:14, col:25> 'void (void)' CXXMethod 0x3861500 'MyFunc' 'void (void)')))))
Добро пожаловать... ;-)
спасибо за указание опции синтаксического дампа.
Номера строк изменены.
5

void TestClass::PrintMyFuncAddress(void)
{
  void (TestClass::* ptrtofn)() = &TestClass::MyFunc;
  cout << (void*&)ptrtofn<< endl;
}

рабочий пример:http://ideone.com/1SmjW

Эту программу демонстрируют очень мало. Этот бросок в стиле C являетсяreinterpret_cast который обычно просто интерпретирует память как тип назначения. В этом случае он будет использовать первыйsizeof(void*) байты хранятся в указателе на член, как если бы это былоvoid*, но если вы проверите размеры обоих типов, вы увидите, что они различаются (указатель на член больше).
@ DavidRodr & # xED; guez-dribeas: Но он должен (вероятно) печатать то же значение, что и & quot;% p & quot; из printf (). Оба они, вероятно, ошибочны (при условии, что указатели на элементы больше, чем обычные указатели (обычно это правда)).

Похожие вопросы