come tutti sapranno setjump soffre di un piccolo problemino:
quando si esegue un "salto",da una funzione ad un'altra, tutte le variabili automatiche saranno indefinite.
Questo non è un problemino da poco e sta nel fatto che la setjump non ripristina lo stack,inizialmente avevo provato a riscrivere da zero (interamente in assembly) la setjmp a mi sono poi reso conto che gestire lo stack diventava non poi cosi semplice.Ho poi trovato una tecnica semplice ma efficace,e senza dover scrivere codice di complessità elevata,ma passiamo subito al codice:
Tutto quello che ci serve è creare solo un file ad esempio "easyjmp.h" (per dovere di cronaca easy è il suffisso del mio framework personale)
#ifndef EASYJMP_H_INCLUDED
#define EASYJMP_H_INCLUDED
#include <windows.h>
#include <setjmp.h>
typedef struct _jmp_buf_safe
{
int retc;
CONTEXT cx;
int retj;
jmp_buf jb;
}jmp_buf_safe;
#define jmp_set(jbs) ((jbs.retc=GetThreadContext(GetCurrentThread(),&jbs.cx)) && (jbs.retj=setjmp(jbs.jb)))
#define jmp_safe(jbs) SetThreadContext(GetCurrentThread(),&jbs.cx)
#define jmp_long(jbs,r) longjmp(jbs.jb,r)
#endif // EASYJMP_H_INCLUDED
Come funziona? semplice utilizzando l'api set/get context facciamo fare tutto il lavoro "sporco" della gestione degli stack a windows e noi saltiamo con piu sicurezza.
Ho racchiuso tutto in delle definizioni e ricreato una semplice struttura solo per semplificarne l'uso.
L'unica spiegazione sono le due variabili retc e retj,la prima ritorna se si è riusciti a ripristinare il contesto e la seconda ritorna il valore del longjmp.
Ora farò un esempio veloce,uno di quelli che con la classica setjmp non avrebbe portato i risultati corretti:
#include <stdio.h>
#include <stdlib.h>
#include "easyjmp.h"
jmp_buf_safe jbs;//Il buffer del salto
void ingiroperilmondo()
{
puts("e salto");
jmp_long(jbs,1);
}
int main(int argc, char *argv[])
{
puts("Hello world\n");
int a=10;
int b=20;
printf("creo due variabili di valore:a=%d b=%d\n\n",a,b);
puts("Setto il salto");
if (jmp_set(jbs)==0) //imposto il salto
{
a++;
b++;
printf("aggiungo uno e ottengo:a=%d b=%d\n",a,b);
puts("vado in giro per il programma...");
ingiroperilmondo();
}
else if (!jbs.retc) //se non ho salvato correttamente il contesto (opzionale)
{
puts("Non riesco a riprisinare il contesto!\n");
return -1;
}
else if (jbs.retj==1)// qui arrivo col salto chiamato prima
{
if (!jmp_safe(jbs))//controllo che posso ripristinare il context
{
puts("impossibile ripristinare il contesto esco per sicurezza.");
return -1;
}
printf("i valori continuano a essere quelli giusti:a=%d b=%d\n\n",a,b);
}
else
{
puts("salto imprevisto");
return -1;
}
puts("Good by world");
return 0;
}
Sicuramente non sarò stato chiaro ma sono sempre qui a rispondere alle vostre domande,non state li troppo a chiedervi perchè ho dovuto creare questa funzione a breve pubblicherò un'altro tips che farà uso "massiccio" di questa nuova funzionalità per semplificarci non di poco la vita con i nostri programmi c, quindi a presto.
Mi sono scordato forse la cosa piu importante,ho usato l'ide CODE::BLOCK col compilatore di default MinGW e sotto Windows Xp
[MODIFICA]
mi sono dimenticato di aggiungere una riga di codice nel test...modificato --
[/MODIFICA]