2012-06-20 20 views
13

Sembra std::cout Non è possibile stampare l'indirizzo di funzione membro, ad esempio:Come stampare l'indirizzo funzione membro in 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; 
} 

il risultato è qualcosa di simile:

003111DB 
1 

Come posso stampare l'indirizzo di MyFunc usando std::cout?

risposta

16

Non credo che ci siano servizi forniti dalla lingua per farlo. Esistono sovraccarichi per operator << per i flussi che stampano i normali puntatori void*, ma i puntatori funzione membro non sono convertibili in void* s. Questo è tutto specifico dell'implementazione, ma in genere i puntatori di funzioni dei membri vengono implementati come una coppia di valori - un indicatore che indica se la funzione membro è virtuale o meno e alcuni dati aggiuntivi. Se la funzione è una funzione non virtuale, tale informazione aggiuntiva è in genere l'indirizzo della funzione membro effettivo. Se la funzione è una funzione virtuale, quell'informazione aggiuntiva probabilmente contiene dati su come indicizzare nella tabella delle funzioni virtuali per trovare la funzione da chiamare dato l'oggetto destinatario.

In generale, penso che questo significhi che è impossibile stampare gli indirizzi delle funzioni membro senza invocare un comportamento indefinito. Probabilmente dovresti usare qualche trucco specifico del compilatore per ottenere questo effetto.

Spero che questo aiuti!

+0

Per alcune interessanti statistiche sulle dimensioni e le implementazioni di puntatori-a-membri funzioni in vari compilatori, vedere la tabella nella parte inferiore di [questo articolo] (http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible). Tuttavia, poiché tale articolo è un po 'datato (scritto nel 2005), i numeri probabilmente non sono più accurati, ma danno un'idea approssimativa. –

4

Un modo per farlo è (io non sono sicuro che è portatile):

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

esempio funzionante: http://ideone.com/1SmjW

+3

Quel programma dimostra molto poco. Questo cast in stile C è un 'reinterpret_cast' che di solito reinterpreta la memoria solo come tipo di destinazione. In questo caso, utilizzerà i primi 'sizeof (void *)' byte memorizzati nel puntatore al membro come se fosse un 'void *', ma se controlli le dimensioni di entrambi i tipi vedrai che differiscono (puntatore per membro è più grande). –

+0

@ DavidRodríguez-dribeas: Ma dovrebbe (probabilmente) stampare lo stesso valore di "% p" di printf(). Probabilmente entrambi hanno torto (supponendo che i puntatori dei membri siano più grandi dei normali puntatori (di solito veri)). –

13

vorrei aggiungere alle altre risposte, che la ragione per cui viene stampato '1' invece di un indirizzo, è che, per qualche ragione, il compilatore sta forzando il tuo puntatore di funzione in un booleano, così stai chiamando davvero ostream& operator<< (bool val);

Questo sembra non essere correlato alla funzione essendo un membro f unzione.

si può scoprire questo tipo di informazioni con clangore ++ -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

I numeri di riga sono cambiati. –

+1

grazie per aver segnalato l'opzione di dumping della sintassi. – fduff

+0

Siete i benvenuti ... ;-) –

1

puntatori a funzioni membro hanno bisogno di memoria, anche. Hanno anche una taglia. Così come sulla stampa la memoria del puntatore:

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

Si può usare in questo modo:

class TestClass 
{ 
    void foo(); 
}; 

... 

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