wake-up-neo.net

Bestimmen, auf welche Funktion ein Zeiger in C zeigt?

Ich habe einen Zeiger auf die Funktion, nehme jede Signatur an ... und ich habe 5 verschiedene Funktionen mit derselben Signatur.

Zur Laufzeit wird einer von ihnen dem Zeiger zugewiesen, und diese Funktion wird aufgerufen.

Wie kann ich den Funktionsnamen, auf den der Zeiger derzeit zeigt, erfahren, ohne eine Druckanweisung in diese Funktionen einzufügen?

53
Sumit

Sie müssen prüfen, auf welche Ihrer 5 Funktionen Ihr Zeiger zeigt:

if (func_ptr == my_function1) {
    puts("func_ptr points to my_function1");
} else if (func_ptr == my_function2) {
    puts("func_ptr points to my_function2");
} else if (func_ptr == my_function3) {
    puts("func_ptr points to my_function3");
} ... 

Wenn dies ein allgemeines Muster ist, das Sie benötigen, verwenden Sie anstelle eines Funktionszeigers eine Tabelle mit Strukturen: 

typedef void (*my_func)(int);

struct Function {
    my_func func;
    const char *func_name;
};

#define FUNC_ENTRY(function) {function, #function}

const Function func_table[] = {
    FUNC_ENTRY(function1),
    FUNC_ENTRY(function2),
    FUNC_ENTRY(function3),
    FUNC_ENTRY(function4),
    FUNC_ENTRY(function5)
}

struct Function *func = &func_table[3]; //instead of func_ptr = function4;

printf("Calling function %s\n", func->func_name);
func ->func(44); //instead of func_ptr(44);
65
nos

Im Allgemeinen stehen solche Dinge in C für den Programmierer nicht zur Verfügung.

Möglicherweise gibt es systemspezifische Methoden, um mit Hilfe von Debugsymbolen usw. dorthin zu gelangen, aber Sie möchten sich wahrscheinlich nicht darauf verlassen, dass das Programm normal funktioniert.

Sie können natürlich den Wert des Zeigers mit einem anderen Wert vergleichen, z.

if (ptr_to_function == some_function)
    printf("Function pointer now points to some_function!\n");
27
janneb

Die Funktionsnamen sind zur Laufzeit nicht verfügbar.

C ist keine reflektierende Sprache.

Entweder pflegen Sie eine Tabelle von Funktionszeigern, die nach ihrem Namen eingegeben werden, oder geben Sie einen Modus für die Funktion Aufruf jeder Funktion an, die den Namen zurückgibt.

16
Bathsheba

Der Debugger kann Ihnen dies sagen (d. H. Den Namen einer Funktion, wenn ihre Adresse angegeben ist).

Auch die Symboltabelle einer nicht gestrippten ELF -Datei kann hilfreich sein. Siehe nm (1) , objdump (1) , readelf (1)

Ein anderer Linux-GNU/libc-spezifischer Ansatz könnte darin bestehen, zur Laufzeit die Funktion dladdr (3) zu verwenden. Angenommen, Ihr Programm ist schön und dynamisch verknüpft (z. B. mit -rdynamic), und es kann den Namen des Symbols und den gemeinsam genutzten Objektpfad finden, wenn ihm eine Adresse (einer global benannten Funktion) zugewiesen wird.

Wenn Sie nur fünf Funktionen für eine bestimmte Signatur haben, können Sie natürlich Ihre Adresse (mit den fünf Adressen) vergleichen.

Beachten Sie, dass einige Funktionen keine (global sichtbaren) Namen haben, beispielsweise static-Funktionen.

Und einige Funktionen könnten dlopen_ed und dlsym_ed sein (z. B. in Plugins). Oder ihr Code kann zur Laufzeit von einem JIT-ing-Framework (libjit, gccjit, LLVM, asmjit) synthetisiert werden. Und der optimierender Compiler kann (und macht!) Inline-Funktionen, klont sie, Tail-Call usw., so dass Ihre Frage im Allgemeinen keinen Sinn ergibt. .

Siehe auch backtrace (3) & Ian Taylors libbacktrace in GCC.

Im Allgemeinen ist Ihre Suche jedoch unmöglich. Wenn Sie solche reflektierenden Informationen wirklich auf zuverlässige Weise benötigen, können Sie sie selbst verwalten (siehe Pitrat's CAIA -System als Beispiel oder irgendwie mein MELT -System), indem Sie vielleicht einige davon erzeugen Code während des Builds.

15

Um zu wissen, wo ein Funktionszeiger zeigt, müssen Sie mit Ihrem Programm den Überblick behalten. Am gebräuchlichsten ist es, ein Array von Funktionszeigern zu deklarieren und eine int-Variable als Index dieses Arrays zu verwenden.

Allerdings ist es heutzutage auch möglich, zur Laufzeit über die __func__-Kennung festzustellen, welche Funktion gerade ausgeführt wird:

#include <stdio.h>

typedef const char* func_t (void);

const char* foo (void)
{
  // do foo stuff
  return __func__;
}

const char* bar (void)
{
  // do bar stuff
  return __func__;
}

int main (void)
{
  func_t* fptr;

  fptr = foo;
  printf("%s executed\n", fptr());

  fptr = bar;
  printf("%s executed\n", fptr());

  return 0;
}

Ausgabe:

foo executed
bar executed
13
Lundin

Überhaupt nicht - der symbolische Name der Funktion verschwindet nach dem Übersetzen. Im Gegensatz zu einer reflektierenden Sprache weiß C nicht, wie die Syntaxelemente vom Programmierer benannt wurden. Insbesondere gibt es nach der Kompilierung keine "Funktionssuche" nach Namen.

Sie können natürlich eine "Datenbank" (z. B. ein Array) mit Funktionszeigern haben, mit denen Sie Ihren aktuellen Zeiger vergleichen können.

10
Marcus Müller

Das ist absolut schrecklich und nicht tragbar, vorausgesetzt jedoch:

  1. Sie sind unter Linux oder einem ähnlichen, ELF-basierten System.
  2. Sie verwenden dynamisches Linken.
  3. Die Funktion befindet sich in einer gemeinsam genutzten Bibliothek oder Sie haben beim Verknüpfen -rdynamic verwendet.
  4. Wahrscheinlich viele andere Annahmen, die Sie nicht machen sollten ...

Sie können den Namen einer Funktion erhalten, indem Sie ihre Adresse an die nicht standardmäßige dladdr - Funktion übergeben.

8
R..
  1. stellen Sie Ihren Linker so ein, dass er eine MAP-Datei ausgibt.
  2. das Programm anhalten
  3. Überprüfen Sie die im Zeiger enthaltene Adresse.
  4. suchen Sie die Adresse in der MAP-Datei, um herauszufinden, auf welche Funktion verwiesen wird.
3
Mark Ch

Ein Zeiger auf eine C-Funktion ist wie jeder Zeiger eine Adresse. Sie können den Wert von einem Debugger erhalten. Sie können den Zeiger auf einen beliebigen Integer-Typ mit genügend Bits setzen, um ihn vollständig auszudrücken und zu drucken. Jede Übersetzungseinheit, die den Zeiger verwenden kann, dh den Funktionsnamen im Gültigkeitsbereich hat, kann die Zeigerwerte drucken oder mit einer Laufzeitvariablen vergleichen, ohne irgendetwas innerhalb der Funktionen selbst zu berühren.

0
Bill IV