Bestimmen, auf welche Funktion ein Zeiger in C zeigt?

Lesezeit: 7 Minuten

Benutzeravatar von Sumit
Gipfel

Ich habe einen Zeiger auf die Funktion, nehme eine beliebige Signatur an. Und ich habe 5 verschiedene Funktionen mit derselben Signatur.

Zur Laufzeit wird eine davon dem Zeiger zugewiesen und diese Funktion aufgerufen.

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

  • Der Name einer Funktion ist nur ein Hilfsmittel für Programmierer. Während der Laufzeit hat das Programm keine Vorstellung von Funktionsnamen (außer vielleicht, wenn es kompiliert wurde, um Debugging-Symbole hinzuzufügen).

    – Cadaniluk

    19. Oktober 2015 um 13:14 Uhr

  • Sie können nicht, und für andere Zwecke als das Debuggen sollten Sie es auch nicht müssen.

    – Dariusz

    19. Oktober 2015 um 13:21 Uhr

  • @cad Außer wenn Sie die Standardkennung hinzufügen __func__ in den Code, in welchem ​​Fall der Compiler ein String-Literal entsprechend dem Funktionsnamen in das Programm einbindet.

    – Ludin

    19. Oktober 2015 um 13:23 Uhr

  • Ja, es gibt diesen neuen schicken C99-Standard, lasst uns feiern, als wäre es 1999 🙂

    – Ludin

    19. Oktober 2015 um 13:33 Uhr

  • @Sumit: warum genau fragst du? Bitte Bearbeiten Sie Ihre Frage um zu erklären warum und es zu verbessern…

    – Basile Starynkevitch

    19. Oktober 2015 um 14:01 Uhr

Benutzeravatar von nos
Nr

Sie müssen überprü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 eine Tabelle mit Strukturen anstelle eines Funktionszeigers:

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

  • func_table->func sollte sein func-> um den ausgewählten Eintrag hier zu verwenden [3] nicht immer Eintrag [0].

    – dave_thompson_085

    19. Oktober 2015 um 23:09 Uhr

Im Allgemeinen stehen solche Dinge in C dem Programmierer nicht zur Verfügung.

Es mag systemspezifische Möglichkeiten geben, dorthin zu gelangen, indem Sie Debug-Symbole usw. verwenden, aber Sie möchten sich wahrscheinlich nicht darauf verlassen, dass diese vorhanden sind, damit das Programm normal funktioniert.

Aber 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");

  • In C solche Dinge sind tatsächlich verfügbar für den Programmierer durch die __func__ Kennung.

    – Ludin

    19. Oktober 2015 um 13:25 Uhr

  • @Lundin Aber ist das nicht nur in der verfügbar Karosserie der Funktion? Das OP möchte den Namen aus finden ptr_to_function allein.

    – Hagen von Eitzen

    19. Oktober 2015 um 18:44 Uhr

  • @Lundin, das ist eine Präprozessordirektive, die den aktuellen Namen der Funktion erhält, die derzeit einen Geltungsbereich hat, der nicht einmal im Entferntesten auf die Frage zutrifft.

    – Sam

    19. Oktober 2015 um 19:12 Uhr

  • @Sam __func__ ist nur innerhalb der Funktion verfügbar und daher hier keine gute Antwort, aber es ist eine normale (genau TP7) Kennung, kein Präprozessor-Makro wie __FILE__ und __LINE__noch eine Direktive wie #if.

    – dave_thompson_085

    19. Oktober 2015 um 23:08 Uhr


Benutzeravatar von Bathsheba
Bathseba

Die Funktionsnamen sind zur Laufzeit nicht verfügbar.

C ist nicht a reflektierend Sprache.

Pflegen Sie entweder eine Tabelle mit Funktionszeigern, die nach ihrem Namen verschlüsselt sind, oder geben Sie einen Modus von an Berufung jede Funktion, die den Namen zurückgibt.

  • reflektierend war das Wort, das mir fehlte. Hut ab!

    – Markus Müller

    19. Oktober 2015 um 13:18 Uhr

  • Und so wurde die Antwort der Nachdenklichkeit geschrieben.

    – Markus Müller

    19. Oktober 2015 um 13:20 Uhr

  • Außer wenn Sie die Standardkennung hinzufügen __func__ in den Code, in welchem ​​Fall der Compiler ein String-Literal entsprechend dem Funktionsnamen in das Programm einbindet.

    – Ludin

    19. Oktober 2015 um 13:23 Uhr

Benutzeravatar von Basile Starynkevitch
Basile Starynkevitch

Der Debugger könnte Ihnen das mitteilen (dh den Namen einer Funktion anhand ihrer Adresse).

Die Symboltabelle eines unstripped ELF ausführbare Datei könnte auch helfen. Sehen nm(1), objdump(1), readelf(1)

Ein weiterer Linux GNU/libc-spezifischer Ansatz könnte darin bestehen, zur Laufzeit die dladdr(3) Funktion. Angenommen, Ihr Programm ist schön und dynamisch verlinkt (z -rdynamic), kann es den Symbolnamen und den gemeinsam genutzten Objektpfad finden, wenn eine Adresse (einer global benannten Funktion) gegeben ist.

Wenn Sie nur fünf Funktionen einer bestimmten Signatur haben, könnten Sie natürlich Ihre Adresse (mit den fünf Adressen davon) vergleichen.

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

Und einige Funktionen könnten sein dlopen-ed und dlsym-ed (z. B. innerhalb von Plugins). Oder ihr Code wird zur Laufzeit von einem JIT-ing-Framework synthetisiert (libjit, gccjit, LLVM, asmjit). Und die Compiler optimieren kann (und tut!) Inline-Funktionen, klonen sie, Tail-Call sie usw. … also macht Ihre Frage im Allgemeinen keinen Sinn …

Siehe auch Rückverfolgung(3) & Ian Taylors libbacktrace innerhalb von GCC.

Aber im Allgemeinen ist Ihre Suche unmöglich. Wenn Sie solche reflektierenden Informationen wirklich auf zuverlässige Weise benötigen, verwalten Sie sie selbst (sehen Sie in Pitrats CAIA System als Beispiel, oder irgendwie mein SCHMELZEN system), möglicherweise durch Generieren von Code während des Builds.

Um zu wissen, wohin ein Funktionszeiger zeigt, müssen Sie mit Ihrem Programm den Überblick behalten. Am häufigsten wird ein Array von Funktionszeigern deklariert und eine int-Variable als Index dieses Arrays verwendet.

Allerdings kann man heutzutage auch zur Laufzeit feststellen, welche Funktion gerade ausgeführt wird, indem man die verwendet __func__ Kennung:

#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

  • Dies ist vergleichbar mit dem Einfügen einer print-Anweisung in die Funktion. Ich habe diese Einschränkung so verstanden, dass Sie den Code innerhalb der Funktion nicht ändern können.

    – Ratschenfreak

    19. Oktober 2015 um 14:41 Uhr

  • Dies erfordert auch, dass die Funktionen a zurückgeben const char * (oder eine gleichwertige Einschränkung des Prototyps). Dies erfordert auch von Ihnen Anruf die Funktion…

    – Oliver Charlesworth

    19. Oktober 2015 um 21:56 Uhr

  • @ratchetfreak Entweder müssen Sie wissen, welche Funktion aufgerufen wurde, was dies löst. Oder Sie müssen wissen, welche Funktion Sie aufrufen … was nicht viel Sinn macht. Wie kam es dazu, dass Sie nicht wussten, welche Funktion Sie aufrufen? Grundlegendes Programmdesign löst das: Erstellen Sie, wie in der Antwort erwähnt, ein Array und eine Indexvariable, so einfach ist das.

    – Ludin

    20. Oktober 2015 um 6:12 Uhr


User-Avatar von Marcus Müller
Markus Müller

Überhaupt nicht – der symbolische Name der Funktion verschwindet nach dem Kompilieren. Im Gegensatz zu einer reflektierenden Sprache weiß C nicht, wie seine 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) von Funktionszeigern haben, mit denen Sie Ihren aktuellen Zeiger vergleichen können.

  • Dies ist vergleichbar mit dem Einfügen einer print-Anweisung in die Funktion. Ich habe diese Einschränkung so verstanden, dass Sie den Code innerhalb der Funktion nicht ändern können.

    – Ratschenfreak

    19. Oktober 2015 um 14:41 Uhr

  • Dies erfordert auch, dass die Funktionen a zurückgeben const char * (oder eine gleichwertige Einschränkung des Prototyps). Dies erfordert auch von Ihnen Anruf die Funktion…

    – Oliver Charlesworth

    19. Oktober 2015 um 21:56 Uhr

  • @ratchetfreak Entweder müssen Sie wissen, welche Funktion aufgerufen wurde, was dies löst. Oder Sie müssen wissen, welche Funktion Sie aufrufen … was nicht viel Sinn macht. Wie kam es dazu, dass Sie nicht wussten, welche Funktion Sie aufrufen? Grundlegendes Programmdesign löst das: Erstellen Sie, wie in der Antwort erwähnt, ein Array und eine Indexvariable, so einfach ist das.

    – Ludin

    20. Oktober 2015 um 6:12 Uhr


R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Das ist absolut schrecklich und nicht tragbar, aber vorausgesetzt:

  1. Sie verwenden Linux oder ein ähnliches ELF-basiertes System.
  2. Sie verwenden dynamische Verknüpfungen.
  3. Die Funktion befindet sich in einer gemeinsam genutzten Bibliothek oder Sie verwendet -rdynamic beim Verlinken.
  4. Wahrscheinlich viele andere Annahmen, die Sie nicht machen sollten …

Sie können den Namen einer Funktion erhalten, indem Sie ihre Adresse an den Nichtstandard übergeben dladdr Funktion.

1411320cookie-checkBestimmen, auf welche Funktion ein Zeiger in C zeigt?

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

Privacy policy