2013-03-06 12 views
8

Sto scrivendo un codice multipiattaforma che deve utilizzare un puntatore per impostare jmp/sigsetjmp. Normalmente questo sarebbe semplice come fareMacro inferno: puntatore indipendente dalla piattaforma per setjmp/sigsetjmp

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

Tuttavia, ISO e POSIX stato che setjmp/sigsetjmp può essere definito come una macro, e in effetti questo è il caso nella mia casella di Linux. Ecco un estratto dal /usr/include/setjmp.h:

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

Il problema è che, dal momento che non sto passando argomenti per sigsetjmp, la macro non espandere e il sigsetjmp simbolo pianura non è definito nella libc. Speravo di poter usare qualche macro "magia nera" per estrarre il nome "__sigsetjmp", ma finora ho fallito miseramente.

Un'altra opzione potrebbe utilizzare __sigsetjmp direttamente ma ciò implicherebbe il controllo dell'espansione per ogni piattaforma supportata, che non voglio fare (da qui il motivo di questa domanda).

PS: Odio i macro.

Nota:

La ragione per cui ho bisogno di questo è un po 'oscuro, ma per semplificare, diciamo che voglio eseguire confronti puntatore con esso.

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

Edit:

Sì, sì. So che non dovrei contare sul fatto di ottenere un puntatore su sigsetjmp perché potrebbe non essere nemmeno una funzione in alcune piattaforme, ma lo non risolve il mio problema.

In pratica, tutte le piattaforme che conosco implementano come funzione.

Sono in grado di far fronte al fatto che, in pochi anni, mi imbatto in un caso in cui non è una funzione per determinate piattaforme. Ma quello che non mi piacerebbe affrontare è passare attraverso ogni piattaforma supportata e controllare setjmp.h per le definizioni di macro, che è la mia unica opzione al momento.

Apprezzo i riferimenti agli standard ma mi piacerebbe avere una risposta pratica non uno purista uno.

+2

Btw., La trasmissione di un puntatore a un 'void *' è anch'essa non portabile. –

+0

C'è una vera ragione per questo, ma è piuttosto lungo da spiegare (riguarda il wrapping delle funzioni). Fidati di me, ho bisogno di quel puntatore :) – fons

+0

@larsmans true, volevo solo fornire un esempio semplificato. Dare un tipo corretto a p non cambia il problema. – fons

risposta

2

Non si può fare questo portabile, come lo standard vieta esplicitamente (§7.13):

E 'specificato se setjmp è una macro o un identificatore dichiarato con esterno collegamento. Se una definizione macro viene soppressa per accedere a una funzione effettiva (...) , il comportamento non è definito.

Al che POSIX aggiunge che

La funzione sigsetjmp() deve essere equivalente alla funzione setjmp()

con alcune eccezioni che sono irrilevanti qui.

Per quanto riguarda la sua osservazione

tutte le piattaforme che conosco implementano come una funzione

In GCC, setjmp è un built-in, e credo in Clang, quindi è sigsetjmp. (Anche se la libreria C potrebbe avere una versione di funzione pure.)

+0

Grazie per il riferimento allo standard. Hai ragione, non dovrei fare affidamento sulla funzione, ma purtroppo ho bisogno di farlo. E in pratica non porterà a comportamenti indefiniti per tutte le piattaforme che supportiamo. – fons

+0

@fons: se hai un gruppo limitato di piattaforme da supportare e vuoi eseguire la magia nera, la soluzione è di mantenere un elenco di '# ifdef's che gestiscono i casi che ti interessano. Ma attenzione che il il comportamento è ancora indefinito "in pratica" perché una nuova versione del compilatore o della libreria potrebbe interrompere il programma. Stai effettivamente legando te stesso a una versione del compilatore, una versione di libreria e una serie di flag del compilatore che fanno funzionare il tuo programma. –

+0

Puoi mostrare la prova che 'setjmp' è incorporato in GCC? Posso chiaramente vederlo essere dichiarato come una funzione (senza macro) in /usr/include/sejmp.h. 'extern int setjmp (jmp_buf __env) __THROWNL;' – fons

-1

Per quello che dici che vuoi, vorrei fare qualcosa di simile:

#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 

Questo vi darà una funzione sigsetjmp si può prendere l'indirizzo di, ma non si può davvero chiamare ...

+0

Non sono sicuro di seguirlo. Questo codice non si espanderebbe semplicemente in "int sigsetjmp (sigjmp_buf env, int savesigs) {...}'? Quindi potrei ottenere l'indirizzo della funzione 'sigsetjmp' che abbiamo appena definito, ma sarebbe diverso dall'indirizzo di' __sigsetjmp', che è quello che voglio. – fons

+0

@fons: questa è l'idea. La funzione '__sigsetjmp' è solo un'implementazione specifica di sigsetjmp - altre soluzioni basate su macro fanno qualcosa di diverso. Se sigsetjmp è una macro, non è possibile (in generale) ottenere un puntatore a funzione che è possibile chiamare, poiché anche se esiste una funzione, è probabile che gli argomenti siano stati massaggiati (motivo per cui è necessaria la macro). –

+0

Beh, questo non è quello che stavo cercando, ma grazie :) – fons

0

ne dite:

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

quindi utilizzare l'indirizzo del & my_sigsetjmp