2012-06-20 14 views
13

to wygląda std::cout nie można wydrukować adres funkcja użytkownika, na przykład:Jak drukować adres funkcji członka w C++

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

wynik jest coś takiego:

003111DB 
1 

Jak mogę wydrukować adres MyFunc za pomocą std::cout?

Odpowiedz

16

Nie wierzę, że w tym języku są dostępne języki. Występują przeciążenia dla operator << dla strumieni w celu wydrukowania normalnych wskaźników void*, ale wskaźniki funkcji elementów nie mogą być przekształcane na void* s. To wszystko zależy od implementacji, ale zwykle wskaźniki funkcji członka są zaimplementowane jako para wartości - flaga wskazująca, czy funkcja członkowska jest wirtualna, czy kilka dodatkowych danych. Jeśli funkcja jest funkcją inną niż wirtualna, ta dodatkowa informacja jest zwykle adresem rzeczywistej funkcji elementu. Jeśli funkcja jest funkcją wirtualną, ta dodatkowa informacja prawdopodobnie zawiera dane o tym, jak zaindeksować w tabeli funkcji wirtualnych, aby znaleźć wywoływaną funkcję, biorąc pod uwagę obiekt odbiorcy.

Ogólnie rzecz biorąc, myślę, że oznacza to, że niemożliwe jest wydrukowanie adresów funkcji członkowskich bez wywoływania niezdefiniowanych zachowań. Prawdopodobnie będziesz musiał użyć sztuczki specyficznej dla kompilatora, aby osiągnąć ten efekt.

Mam nadzieję, że to pomoże!

+0

Dla ciekawych statystyk dotyczących wielkości i wdrożeń wskaźników-do państwie funkcje w różnych kompilatory, zobacz wykres u dołu [tego artykułu] (http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-TheFastest-Possible). Ponieważ jednak artykuł ten jest nieco przestarzały (napisany w 2005 r.), Liczby prawdopodobnie nie są już dokładne, ale dają z grubsza odpowiedź. –

4

Jednym ze sposobów na to jest (nie jestem pewien, że to przenośne):

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

przykład praca: http://ideone.com/1SmjW

+3

Ten program demonstruje bardzo mało. Ten rzut w stylu C jest "reinterpret_cast", który zwykle po prostu ponownie interpretuje pamięć jako typ docelowy. W tym przypadku użyje pierwszego bajtu 'sizeof (void *)' przechowywanego w wskaźniku do elementu tak, jakby był 'void *', ale jeśli sprawdzisz rozmiary obu typów, zobaczysz, że różnią się one (wskaźnik członek jest większy). –

+0

@ DavidRodríguez-dribeas: Ale powinien (prawdopodobnie) wydrukować taką samą wartość, jak "% p" printf(). Oba są prawdopodobnie błędne (zakładając, że wskaźniki członków są większe niż normalne wskaźniki (zwykle prawdziwe)). –

13

Chciałbym dodać do innych odpowiedzi, że z powodu, że zamiast adresu drukowany jest "1", jest to, że z jakiegoś powodu kompilator zmusza wskaźnik funkcji do wartości boolowskiej, tak więc naprawdę wywołujemy tę funkcję, więc naprawdę wywołujemy tę funkcję, więc wydaje się, że nie ma ona związku z funkcją członek f namaszczenie.

można odkryć tego rodzaju informacji z brzękiem ++ -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)'))))) 
+0

Numery linii zostaną zmienione. –

+1

dzięki za wskazanie opcji zrzutu składni. – fduff

+0

Serdecznie zapraszamy ... ;-) –

1

Wskaźniki do funkcji składowych potrzeba pamięci, zbyt. Mają też rozmiar. Tak jak o drukowaniu pamięć wskaźnika:

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

można użyć go w ten sposób:

class TestClass 
{ 
    void foo(); 
}; 

... 

std::cout << to_string(&TestClass::foo) << std::endl; 
Powiązane problemy