Wie drucke ich Funktionszeiger mit cout?

Lesezeit: 1 Minute

Wie drucke ich Funktionszeiger mit cout
ibrot

Ich möchte einen Funktionszeiger mit cout ausdrucken und habe festgestellt, dass es nicht funktioniert hat. Aber es hat funktioniert, nachdem ich den Funktionszeiger in (void *) konvertiert habe, also auch printf mit %p, wie z

#include <iostream>
using namespace std;

int foo() {return 0;}

int main()
{
    int (*pf)();
    pf = foo;
    cout << "cout << pf is " << pf << endl;
    cout << "cout << (void *)pf is " << (void *)pf << endl;
    printf("printf(\"%%p\", pf) is %p\n", pf);
    return 0;
}

Ich habe es mit g ++ kompiliert und folgende Ergebnisse erhalten:

cout << pf ist 1
cout << (void *)pf ist 0x100000b0c
printf(“%p”, pf) ist 0x100000b0c

Was also macht cout mit dem Typ int

()? Mir wurde gesagt, dass der Funktionszeiger als bool behandelt wird, ist das wahr? Und was macht cout mit type (void *)?

Vielen Dank im Voraus.

BEARBEITEN: Wie auch immer, wir können den Inhalt eines Funktionszeigers beobachten, indem wir ihn in (void *) umwandeln und ihn mit cout ausdrucken. Aber es funktioniert nicht für Member-Funktionszeiger und der Compiler beschwert sich über die illegale Konvertierung. Ich weiß, dass Member-Funktionszeiger eher eine komplizierte Struktur als einfache Zeiger sind, aber wie können wir den Inhalt von Member-Funktionszeigern beobachten?

ostream & operator <<( ostream &, const void * );

Es gibt tatsächlich eine Überladung des <<-Operators, die ungefähr so ​​​​aussieht:

was tut, was Sie erwarten – gibt in Hex aus. Es kann keine solche Überladung der Standardbibliothek für Funktionszeiger geben, da es unendlich viele Typen davon gibt. Der Zeiger wird also in einen anderen Typ konvertiert, der in diesem Fall ein bool zu sein scheint – ich kann mich nicht ohne Weiteres an die Regeln dafür erinnern. Bearbeiten:

Der C++-Standard spezifiziert:

4.12 Boolesche Konvertierungen

1 Ein Rvalue vom Typ arithmetisch, Enumeration, Zeiger oder Zeiger auf Member kann in einen Rvalue vom Typ bool konvertiert werden.

  • Dies ist die einzige Konvertierung, die für Funktionszeiger angegeben ist. bool+1. Die einzige Standardkonvertierung, die auf einen Zeiger auf eine Funktion anwendbar ist, ist (abgesehen von der lvalue-to-rvalue-Konvertierung) die Konvertierung in reinterpret_cast . Insbesondere müssen Sie durchführen int (*)() umwandeln void *zu

    .

    – Avakar


  • 14. Januar 2010 um 14:40 Uhr

    @avakar Gibt es ein Dokument oder so, das die Konvertierungsregeln von Funktionszeigern abdeckt?

    – Brot

  • 14. Januar 2010 um 14:56 Uhr[conv] Das ultimative Dokument wäre der C++-Standard, Abschnitte 4[expr.post]und 5.2 . Der Standard ist nicht kostenlos, aber Sie können den neuesten Entwurf hier herunterladen:open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf

    . Beachten Sie, dass es schwierig sein kann, es zu lesen, wenn Sie nicht daran gewöhnt sind.

    – Avakar

  • 14. Januar 2010 um 15:09 Uhrvoid * @ Neil: ist das einzigeWandlung , aber es gibt noch etwas zu beachten: Manipulatoren sind Funktionen, deren Adressen Sie an den Stream übergeben. Anstatt sie zu konvertieren, wird der Stream ruft

    Ihnen; Wenn Sie einen Zeiger an eine Funktion mit einer Signatur wie der eines Manipulators übergeben, behandelt der Stream ihn wie einen Manipulator und ruft die Funktion auf, anstatt zu versuchen, ihre Adresse überhaupt zu konvertieren.

    – Jerry Sarg

  • 14. Januar 2010 um 15:22 Uhr

    @Neil Butterworth @avkar Vielen Dank für Ihre Hilfe. Cout behandelt also Funktionszeiger als bool, nachdem es herausgefunden hat, dass es keinen anderen Typ gibt, der konvertiert werden kann, richtig?

    – Brot

14. Januar 2010 um 15:27 Uhr unsigned char In Bezug auf Ihre Bearbeitung können Sie den Inhalt von allem ausdrucken, indem Sie über darauf zugreifen

#include <iostream>
#include <iomanip>

struct foo { virtual void bar(){} };
struct foo2 { };
struct foo3 : foo2, foo { virtual void bar(){} };

int main()
{
    void (foo3::*p)() = &foo::bar;

    unsigned char const * first = reinterpret_cast<unsigned char *>(&p);
    unsigned char const * last = reinterpret_cast<unsigned char *>(&p + 1);

    for (; first != last; ++first)
    {
        std::cout << std::hex << std::setw(2) << std::setfill('0')
            << (int)*first << ' ';
    }
    std::cout << std::endl;
}

  • Zeiger. Ein Beispiel für Zeiger auf Memberfunktionen:

    Vielen Dank! Jetzt weiß ich, wie man den Inhalt des Member-Funktionszeigers beobachtet.

    – Brot

1647101411 616 Wie drucke ich Funktionszeiger mit cout
14. Januar 2010 um 16:18 Uhr

Gregor Bacon boolSie können sich einen Funktionszeiger als die Adresse der ersten Anweisung im Maschinencode dieser Funktion vorstellen. Jeder Zeiger kann als behandelt werden void * : 0 ist falsch und alles andere ist wahr. Wie Sie beobachtet haben, wenn Sie gecastet wurden<<und als Argument an den Stream-Einfügungsoperator ( void * ), wird die Adresse gedruckt. (Streng genommen wird ein Zeiger auf eine Funktion gecastet

ist nicht definiert.)

Ohne die Besetzung ist die Geschichte etwas kompliziert. Für den Abgleich überladener Funktionen (“Überladungsauflösung”) sammelt ein C++-Compiler eine Reihe von Kandidatenfunktionen und wählt aus diesen Kandidaten die “am besten geeignete” aus, falls erforderlich unter Verwendung impliziter Konvertierungen. Das Problem besteht darin, dass die Übereinstimmungsregeln eine Teilreihenfolge bilden, sodass mehrere bestmögliche Übereinstimmungen einen Mehrdeutigkeitsfehler verursachen.

  • In der Reihenfolge der Präferenz sind die Standardkonvertierungen (und natürlich gibt es auch benutzerdefinierte und Ellipsenkonvertierungen, nicht detailliert) aufgeführtgenaue Übereinstimmung (dh
  • keine Konvertierung notwendig)Beförderung (z.B int , floatzu
  • )

andere Umbauten boolDie letzte Kategorie umfasst boolesche Konvertierungen, und jeder Zeigertyp kann konvertiert werden NULL: 0 (bzw false ) ist trueund alles andere ist 1 . Letzteres zeigt sich als

wenn sie an den Stream-Einfügungsoperator übergeben werden. 0 Bekommen

pf = 0;

Ändern Sie stattdessen Ihre Initialisierung in

  • Denken Sie daran, dass die Initialisierung eines Zeigers mit einem konstanten Ausdruck mit Nullwert den Nullzeiger ergibt.

    Sie meinen also, der Compiler neigt dazu, jeden Zeiger ohne bekannten Typ als bool zu behandeln?

    – Brot

  • 14. Januar 2010 um 14:43 Uhr

    @curiousguy Äh … Eigentlich meine ich, wenn der Compiler die genaue Signatur der Funktion, die als Argumente aufgerufen wird, nicht finden kann, sagen wir in diesem speziellen Beispiel einen Funktionszeiger, versucht der Compiler, sie in bool umzuwandeln und damit mit an übereinzustimmen überladene Version mit Argument vom Typ bool.

    – Brot


  • 25. Oktober 2011 um 18:22 Uhr bool@ibread Eigentlich berücksichtigt der Compiler immer alle möglichen Kandidatenfunktionen; Wenn es eine Funktion gibt, die den richtigen Funktionstyp annimmt, ist sie der “beste” Kandidat. Da es keine solche Funktion gibt, ist der einzige Kandidat die Funktionsübernahme

    .

    – Neugieriger

Wie drucke ich Funktionszeiger mit cout
26. Oktober 2011 um 0:14 Uhr

alfC operator<< In C++11 könnte man dieses Verhalten ändern, indem man eine variadische Template-Überladung von definiert

#include<iostream>
namespace function_display{
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ){ // star * is optional
    return os << "funptr " << (void*)p;
}
}

// example code:
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}

int main(){
    using namespace function_display;
    // ampersands & are optional
    std::cout << "1. " << &fun_void_void << std::endl; // prints "1. funptr 0x40cb58"
    std::cout << "2. " << &fun_void_double << std::endl; // prints "2. funptr 0x40cb5e"
    std::cout << "3. " << &fun_double_double << std::endl; // prints "3. funptr 0x40cb69"
}

(ob das empfehlenswert ist oder nicht, ist ein anderes Thema): (void*) Casting-Zeiger auf cout um sie zu drucken

  • ist das Richtige (TM) in C++, wenn Sie ihre Werte sehen möchten.

    Es ist das Richtige, außer natürlich dort, wo es überhaupt nicht funktioniert. Leider gibt es keine Garantie dafür, dass ein Zeiger auf Code wirklich mit einem Zeiger auf Daten kompatibel ist. Ein klassisches Beispiel (heute wirklich klassisch) war das “mittlere” Speichermodell unter MS-DOS, wo ein Zeiger auf Daten nur 16 Bit, aber ein Zeiger auf Code 32 Bit hatte.

    – Jerry Sarg

  • 14. Januar 2010 um 15:17 Uhr unsigned long@JerryCoffin unsigned long long ,

    kann auch verwendet werden.

    – Neugieriger

Wie drucke ich Funktionszeiger mit cout
21. Oktober 2011 um 12:42 Uhr

John Dibling

Zu deiner konkreten Frage,

Wie können wir den Inhalt von Member-Funktionszeigern beobachten?

Die Antwort lautet: Abgesehen davon, dass Sie sie in bool konvertieren, um auszudrücken, dass sie auf etwas zeigen oder nicht, können Sie Member-Funktionszeiger nicht „beobachten“. Zumindest nicht konform. Der Grund dafür ist, dass der Standard dies ausdrücklich verbietet:

4.12 Fußnote 57: 57) Die Regel für die Umwandlung von Zeigern in Elemente (von Zeiger auf Element der Basis in Zeiger auf Element von abgeleitet) erscheint invertiert im Vergleich zur Regel für Zeiger auf Objekte (von Zeiger auf abgeleitet in Zeiger auf Basis) (4.10, Abschnitt 10) . Diese Invertierung ist notwendig, um die Typsicherheit zu gewährleisten. Beachten Sie, dass ein Zeiger auf ein Element kein Zeiger auf ein Objekt oder ein Zeiger auf eine Funktion ist und die Regeln für die Konvertierung solcher Zeiger nicht für Zeiger auf Elemente gelten.

Insbesondere kann ein Zeiger auf Member nicht in ein void* umgewandelt werden.

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;

class Gizmo
{
public:
    void DoTheThing()
    {
        return;
    };


private:
    int foo_;
};

int main()
{
    void(Gizmo::*fn)(void) = &Gizmo::DoTheThing;

    Gizmo g;
    (g.*fn)();  // once you have the function pointer, you can call the function this way

    bool b = fn;
//  void* v = (void*)fn;    // standard explicitly disallows this conversion
    cout << hex << fn;
    return 0;
}

Hier ist beispielsweise Beispielcode: &fnIch stelle fest, dass mein Debugger (MSVC9) mir zur Laufzeit die tatsächliche physische Adresse der Member-Funktion mitteilen kann, sodass ich weiß, dass es eine Möglichkeit geben muss, diese Adresse tatsächlich zu erhalten. Aber ich bin mir sicher, dass es nicht konform und nicht portierbar ist und wahrscheinlich Maschinencode beinhaltet. Wenn ich diesen Weg gehen würde, würde ich damit beginnen, die Adresse des Funktionszeigers (z

), das in void* umwandeln und von dort aus fortfahren. Dies würde auch erfordern, dass Sie die Größe der Zeiger kennen (auf verschiedenen Plattformen unterschiedlich).

Aber ich würde fragen, solange Sie den Member-Funktionszeiger in bool konvertieren und die Existenz des Zeigers auswerten können, warum würden Sie in echtem Code die Adresse benötigen?

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;

class Gizmo
{
public:
    void DoTheThing()
    {
        return;
    };

    **void DoTheOtherThing()
    {
        return;
    };**


private:
    int foo_;
};

int main()
{
    void(Gizmo::*fn)(void) = &Gizmo::DoTheThing;

    Gizmo g;
    (g.*fn)();  // once you have the function pointer, you can call the function this way

    bool b = fn;
//  void* v = (void*)fn;    // standard explicitly disallows this conversion
    cout << hex << fn;

    **void(Gizmo::*fnOther)(void) = &Gizmo::DoTheOtherThing;

    bool same = fnOther == fn;
    bool sameIsSame = fn == fn;**

    return 0;
}

  • Vermutlich lautet die Antwort auf die letzte Frage “damit ich feststellen kann, ob ein Funktionszeiger auf dieselbe Funktion wie ein anderer zeigt”. Fair genug. Sie können Funktionszeiger auf Gleichheit vergleichen:

    Es ist das Richtige, außer natürlich dort, wo es überhaupt nicht funktioniert. Leider gibt es keine Garantie dafür, dass ein Zeiger auf Code wirklich mit einem Zeiger auf Daten kompatibel ist. Ein klassisches Beispiel (heute wirklich klassisch) war das “mittlere” Speichermodell unter MS-DOS, wo ein Zeiger auf Daten nur 16 Bit, aber ein Zeiger auf Code 32 Bit hatte.

    – Jerry Sarg

  • 14. Januar 2010 um 15:17 Uhr unsigned long@JerryCoffin unsigned long long ,

    kann auch verwendet werden.

    – Neugieriger

21. Oktober 2011 um 12:42 Uhr

#include <iostream>     
#include <stdlib.h>

void alexf();

int main()
{ 
    int int_output;

    printf("printf(\"%%p\", pf) is %p\n", alexf);

    asm( "movl %[input], %%eax\n"                
         "movl %%eax, %[output]\n" 
         : [output] "+m" (int_output)
         : [input] "r" (&alexf)
         : "eax", "ebx"
    );

        std::cout<<"" <<std::hex<<int_output <<""<<std::endl;
    return 0;
}

void  alexf() {  }

vielleicht (in einer Zeit bleibe ich über die Adresse der Funktion kreuzen) eine der Entscheidung ))) (&alexf) Übergabe des Zeigers an die Funktion & oder andere Zeiger verwenden rEinschränkung verwenden gcc . Lassen

994280cookie-checkWie drucke ich Funktionszeiger mit cout?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy