2013-03-06 4 views
8

Ich schreibe Multiplattformcode, der einen Zeiger auf setjmp/sigsetjmp verwenden muss. Normalerweise wäre das so einfach wieMakrohölle: Plattformunabhängiger Zeiger auf setjmp/sigsetjmp

tut
#include <setjmp.h> 
void * sigsetjmp_p = sigsetjmp; 

jedoch ISO und POSIX Zustand, der/sigsetjmp setjmp kann als Makro definiert werden, und in der Tat, dass der Fall in meiner Linux-Box. Hier ist ein Auszug aus /usr/include/setjmp.h:

# define sigsetjmp(env, savemask)  __sigsetjmp (env, savemask) 

Das Problem ist, dass, da ich keine Argumente zu sigsetjmp vorbei, wird das Makro nicht erweitern und die Ebene sigsetjmp Symbol nicht in libc definiert. Ich hatte gehofft, dass ich Makro-Schwarzmagie verwenden könnte, um den Namen "__sigsetjmp" zu extrahieren, aber bisher bin ich kläglich gescheitert.

Eine andere Option wäre die direkte Verwendung __sigsetjmp, aber das würde bedeuten, die Erweiterung für jede unterstützte Plattform zu überprüfen, was ich nicht tun möchte (daher der Grund für diese Frage).

PS: Ich hasse Makros.

Hinweis:

Der Grund für die ich brauche das ein bisschen dunkel, aber es zu vereinfachen, sagen wir, ich Zeiger Vergleiche mit ihm ausführen möchten.

#include <setjmp.h> 
int equals_sigsetjmp(void *p) 
{ 
void * sigsetjmp_p = sigsetjmp; 
return p == sigsetjmp_p; 
} 

Edit:

Ja, ja. Ich weiß, dass ich nicht darauf zählen sollte, einen Zeiger auf sigsetjmp zu bekommen, weil es vielleicht nicht einmal eine Funktion in bestimmten Plattformen ist, aber das löst mein Problem nicht.

In der Praxis implementieren alle Plattformen, die ich kenne, es als eine Funktion.

Ich kann mit der Tatsache fertig werden, dass ich in ein paar Jahren, in dem Fall, in dem sigsetjump keine Funktion für bestimmte Plattform ist. Aber was ich nicht bewältigen möchte, ist, jede unterstützte Plattform zu durchlaufen und setjmp.h auf Makrodefinitionen zu überprüfen, was momentan meine einzige Option ist.

Ich schätze die Verweise auf Standards, aber ich würde gerne eine praktische Antwort nicht purist einen bekommen.

+2

Btw., Einen Funktionszeiger auf ein 'void *' zu werfen ist auch nicht tragbar. –

+0

Es gibt einen wirklichen Grund dafür, aber es ist ziemlich lang zu erklären (es beinhaltet das Wrapping von Funktionen). Vertrauen Sie mir, ich brauche diesen Zeiger :) – fons

+0

@larsmans wahr, ich wollte nur ein vereinfachtes Beispiel zur Verfügung stellen. Wenn man p einen richtigen Typ gibt, ändert sich das Problem nicht. – fons

Antwort

2

Sie können dies portably nicht tun, da der Standard explizit verbietet es (§7.13):

Es nicht spezifiziert ist, ob setjmp ein Makro oder eine Kennung mit externen Verknüpfung deklariert ist. Wenn eine Makrodefinition unterdrückt wird, um auf eine tatsächliche Funktion zuzugreifen (...) ist das Verhalten nicht definiert.

Um die POSIX fügt hinzu, dass

Die sigsetjmp() Funktion Äquivalent zum setjmp() Funktion

mit einigen Ausnahmen sein soll, die hier nicht relevant sind.

Was Ihre Bemerkung

alle Plattformen Ich kenne implementieren sie als Funktion

In GCC, setjmp ist eine eingebaute, und ich glaube an Clang, so sigsetjmp ist. (Obwohl die C-Bibliothek könnte eine Funktion Version als auch.)

+0

Danke für die Bezugnahme auf den Standard. Du hast recht, ich sollte mich nicht auf die eigentliche Funktion verlassen, aber leider muss ich. Und in der Praxis wird es nicht zu undefiniertem Verhalten für alle von uns unterstützten Plattformen führen. – fons

+0

@fons: Wenn Sie eine begrenzte Anzahl von Plattformen haben, die unterstützt werden sollen und Sie schwarze Magie ausführen wollen, dann besteht die Lösung darin, eine Liste von '# ifdef's zu führen, die die Fälle behandeln, an denen Sie interessiert sind Verhalten ist in der Praxis immer noch undefiniert, weil eine neue Version des Compilers oder der Bibliothek Ihr Programm beschädigen könnte. Sie binden sich effektiv an eine Compiler-Version, eine Bibliotheksversion und eine Reihe von Compiler-Flags, die Ihr Programm zum Laufen bringen. –

+0

Kannst du beweisen, dass 'setjmp' in GCC eingebaut ist? Ich kann deutlich sehen, dass es als Funktion (ohne Makros) in /usr/include/sejmp.h deklariert ist. 'extern int setjmp (jmp_buf __env) __THROWNL;' – fons

-1

Für das, was Sie sagen, Sie wollen, würde ich so etwas tun:

#include <setjmp.h> 
#ifdef sigsetjmp 
#define AVOID_FUNCTION_MACRO /* expand to nothing */ 
int sigsetjmp AVOID_FUNCTION_MACRO (sigjmp_buf env, int savesigs) { 
    log_fatal_error("Can't call sigsetjmp via pointer, its a macro!"); 
    abort(); 
} 
#endif 

Dies wird Ihnen eine sigsetjmp Funktion können Sie die Adresse nehmen von, aber man kann nicht wirklich nennen es ...

+0

Ich bin mir nicht sicher, ob ich folge. Würde sich dieser Code nicht einfach auf "sigsetjmp (sigjmp_buf env, int savesigs) erweitern? {...}"? Dann könnte ich die Adresse der "sigsetjmp" -Funktion bekommen, die wir gerade definiert haben, aber sie würde sich von der Adresse von "__sigsetjmp" unterscheiden, was ich will. – fons

+0

@fons: das ist die Idee. Die '__sigsetjmp'-Funktion ist nur eine spezifische Implementierung von sigsetjmp - andere makrobasierte Lösungen machen etwas anderes. Wenn sigsetjmp ein Makro ist, können Sie (im Allgemeinen) keinen Funktionszeiger erhalten, den Sie aufrufen können, da selbst wenn es eine Funktion gibt, wahrscheinlich Argumente massiert wurden (weshalb das Makro benötigt wird). –

+0

Nun, das ist nicht was ich gesucht habe, aber danke :) – fons

0

Wie wäre:

void my_sigsetjmp(sigjmp_buf env, int savesigs) 
{ 
    sigsetjmp(env, savesigs); 
} 

Dann die Adresse & my_sigsetjmp verwenden