webentwicklung-frage-antwort-db.com.de

Wie formatiere ich einen Funktionszeiger?

Gibt es eine Möglichkeit, einen Zeiger auf eine Funktion in ANSI C zu drucken? Das bedeutet natürlich, dass Sie den Funktionszeiger auf den ungültigen Zeiger setzen müssen, aber es scheint, dass das nicht möglich ist.

#include <stdio.h>

int main() {
    int (*funcptr)() = main;

    printf("%p\n", (void* )funcptr);
    printf("%p\n", (void* )main);

    return 0;
}

$ gcc -ansi -pedantic -Wall test.c -o test
test.c: In der Funktion 'main':
test.c: 6: Warnung: ISO C verbietet die Konvertierung des Funktionszeigers in den Objektzeigertyp
test.c: 7: Warnung: ISO C verbietet die Konvertierung des Funktionszeigers in den Objektzeigertyp
$ ./test
0x400518
0x400518

Es "funktioniert", aber nicht Standard ...

Der einzige legale Weg, dies zu tun, ist der Zugriff auf die Bytes, aus denen der Zeiger besteht, mit einem Zeichentyp. So was:

#include <stdio.h>

int main() {
    int (*funcptr)() = main;
    unsigned char *p = (unsigned char *)&funcptr;
    size_t i;

    for (i = 0; i < sizeof funcptr; i++)
    {
        printf("%02x ", p[i]);
    }
    putchar('\n');

    return 0;
}

Den Funktionszeiger als void * oder einen beliebigen Nicht-Zeichentyp zu verwenden, wie dies bei dreamlax der Fall ist , ist undefiniertes Verhalten.

Was die Bytes, aus denen der Funktionszeiger besteht, tatsächlich mean ist implementierungsabhängig. Sie könnten beispielsweise nur einen Index in einer Tabelle von Funktionen darstellen.

41
caf

Es gibt die Verwendung von Vereinigungen, die die Warnung/den Fehler umgehen können, aber das Ergebnis ist immer noch (am wahrscheinlichsten) undefiniertes Verhalten:

#include <stdio.h>

int
main (void)
{
  union
  {
    int (*funcptr) (void);
    void *objptr;
  } u;
  u.funcptr = main;

  printf ("%p\n", u.objptr);

  return 0;
}

Sie können zwei Funktionszeiger (z. B. printf ("%i\n", (main == funcptr));) mit einer if -Anweisung vergleichen, um zu testen, ob sie gleich sind oder nicht (ich weiß, dass dies den Zweck völlig außer Kraft setzt und sehr wahrscheinlich irrelevant sein könnte), aber soweit die Adresse der Funktion tatsächlich ausgegeben wird Zeiger, was passiert, liegt beim Hersteller der C-Bibliothek Ihrer Zielplattform und Ihrem Compiler.

5
Dustin

Wandeln Sie den Funktionszeiger in eine Ganzzahl und dann erneut in einen Zeiger um, um "% p" zu verwenden.

#include <stdio.h>

int main() {
    int (*funcptr)() = main;

    printf("%p\n", (void *)(size_t) funcptr);
    printf("%p\n", (void *)(size_t) main);

    return 0;
}

Beachten Sie, dass auf einigen Plattformen (z. B. 16-Bit-DOS in "mittleren" oder "kompakten" Speichermodellen) Zeiger auf Daten und Zeiger auf Funktionen nicht die gleiche Größe haben.

2
dan04

Wenn Sie mit gcc 4.3.4 die Schalter -O2 -Wstrict-Aliasing verwenden, wird die Antwort von dreamlax Folgendes erzeugen:

warning: dereferencing type-punned pointer will break strict-aliasing rules

Hinzugefügt: Ich denke, die Einwände gegen die Antwort von Caf über endianness und Größe sind vernünftig, die seine Lösung nicht anspricht (kein Wortspiel beabsichtigt). Dustins Vorschlag für die Verwendung eines Gewerkschaftsverbandes ist wahrscheinlich legal (obwohl ich aus dem, was ich gelesen habe, eine Debatte zu geben scheint, aber Ihr Compiler ist wichtiger als das Gesetz). Sein Code könnte jedoch durch den Einzeiler vereinfacht (oder verborgen werden, je nach Ihrem Geschmack):

printf("%p\n", ((union {int (*from)(void); void *to;})funcptr).to);

Dadurch wird die gcc-Warnung für striktes Aliasing entfernt (aber ist sie "richtig"?).

Aggregate Casts funktionieren nicht, wenn Sie die Option -pedantic verwenden oder z. SGI IRIX, daher müssen Sie Folgendes verwenden:

printf("%p\n", ((union {int (*from)(void); void *to;} *)&funcptr)->to);

Aber zur ursprünglichen Frage: Ihr Ursprung liegt in der Verwendung von -pedantic, was ich für etwas pedantisch halte :).

Weitere Bearbeitung: Hinweis: Sie können main im letzten Beispiel nicht verwenden, wie in:

printf("%p\n", ((union {int (*from)(void); void *to;})   main).to);  // ok
printf("%p\n", ((union {int (*from)(void); void *to;} *)&main)->to); // wrong!

wegen natürlich & main zerbricht nach main .

1
Joseph Quinsey

Versuche dies:

#include <stdio.h>
#include <inttypes.h>


int main() {
    int (*funcptr)() = main;
    unsigned char *p = (unsigned char *)&funcptr;
    int i;

    /* sample output: 00000000004005e0 */
    printf("%016"PRIxPTR"\n", (uintptr_t)main);
    /* sample output: 00000000004005e0 */
    printf("%016"PRIxPTR"\n", (uintptr_t)funcptr);

    /* reflects the fact that this program is running on little-endian machine
    sample output: e0 05 40 00 00 00 00 00 */
    for (i = 0; i < sizeof funcptr; i++)
    {
        printf("%02x ", p[i]);
    }
    putchar('\n');

    return 0;
}

Benutzt diese Flaggen:

gcc -ansi -pedantic -Wall -O2 -Wstrict-aliasing c.c

Es werden keine Warnungen ausgegeben, die diese Flags verwenden

1
Michael Buen

Ich bin nicht sicher, ob dies koscher ist, aber es erzielt den Effekt ohne Schleife, Vereinigungen, Umwandlungen in Nicht-Zeigertypen oder zusätzliche Abhängigkeiten neben string.h.

int (*funcptr)() = main;
void* p = NULL;
memcpy(&p, (void**) &funcptr, sizeof(funcptr));
printf("%p", p);

Keine Warnungen mit gcc -ansi -pedantic -Wall -Wstrict-aliasing in GCC 7.1.1

0
Jon Deaton